DEV3 Technologies home

DEV3 Developer Forum

How should I handle dates and timezones in PHP correctly?

PHP helpSolved0 views
dev3 ·

My users are in India, US and UK. Dates saved from date('Y-m-d H:i:s') are off by hours depending on server, and adding 1 month to Jan 31 gives March 3. How do I do it properly?

#php#datetime#timezone

0

1 reply

dev3 · Accepted answer

Treat time as UTC in storage and convert to the user's zone only for display.

1. Set a default and store UTC

date_default_timezone_set('UTC');   // or default_timezone in php.ini: date.timezone = UTC
$now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
$db->execute([$now->format('Y-m-d H:i:s')]);

Set the MySQL connection to UTC as well (SET time_zone = '+00:00') if you use NOW().

2. Convert for display

$utc = new DateTimeImmutable($row['created_at'], new DateTimeZone('UTC'));
$local = $utc->setTimezone(new DateTimeZone($user->timezone));   // e.g. 'Asia/Kolkata'
echo $local->format('d M Y, H:i T');

Store the IANA timezone name (America/New_York), not an offset like -05:00, because offsets change with daylight saving time.

3. Prefer DateTimeImmutable

DateTime is mutable: $d->modify('+1 day') changes the original, which causes surprising bugs when you reuse the object. DateTimeImmutable returns a new instance.

$start = new DateTimeImmutable('2026-01-31');
$next = $start->modify('last day of next month');   // 2026-02-28

The "Jan 31 + 1 month = Mar 3" behaviour is PHP overflowing the day. Use last day of next month or Carbon::addMonthNoOverflow() in Laravel.

4. Differences and periods

$diff = $a->diff($b);       // DateInterval
echo $diff->days;           // total days
$period = new DatePeriod($start, new DateInterval('P1D'), $end);

Pitfalls

  • strtotime() and date() use the default zone and are limited to specific formats; ambiguous strings like 03/04/2026 are parsed as US m/d/Y. Parse with DateTimeImmutable::createFromFormat('d/m/Y', $s).
  • Check createFromFormat result with DateTimeImmutable::getLastErrors().
  • Do not calculate 24 hours as a day across DST changes; use calendar modifiers.
  • Timestamps (seconds since 1970) are always UTC.

Handy tools: timestamp converter and time zone converter.

0

Your reply

Every post is reviewed by DEV3 before it appears. Usually reviewed within 24 hours.

Markdown supported. Use ``` for code blocks. Images are not allowed.