Dates7 min readExamples run on PHP 8.5.10

date_timezone_set()

Learn how date_timezone_set() changes the display time zone of a DateTime object without changing the instant it represents, with examples and pitfalls.

Signature

date_timezone_set(DateTime $object, DateTimeZone $timezone): DateTime
Available since PHP 5.2.07.48.08.18.28.38.48.5All versions →

Purpose

date_timezone_set() changes the time zone attached to a DateTime object. It is the procedural alias of DateTime::setTimezone(), so both forms do the same job. The key idea is that the object keeps representing the same moment in time. Only the zone used to describe that moment, and therefore the wall-clock fields you read back, changes.

Signature

Parameters and defaults

  • $object: the mutable DateTime instance to modify. The object is changed in place.
  • $timezone: a DateTimeZone instance describing the new zone, such as new DateTimeZone('Asia/Tokyo').

Neither parameter has a default value. Both are required.

Return value and failure cases

The function returns the same DateTime object that you passed in, now using the new time zone. Because the object is modified in place, the return value is mostly useful for chaining or for a quick assignment. Passing the wrong kind of argument, such as a string instead of a DateTimeZone, or a DateTimeImmutable instead of a DateTime, raises a TypeError. Constructing the DateTimeZone itself with an unknown identifier fails earlier, when you call new DateTimeZone(...), not inside date_timezone_set().

Example 1: converting a UTC time

The first example creates a fixed UTC time and re-expresses it in New York. In January New York uses standard time, which is five hours behind UTC.

Example
<?php
date_default_timezone_set('UTC');
$date = new DateTime('2024-01-15 12:00:00');
date_timezone_set($date, new DateTimeZone('America/New_York'));
echo $date->format('Y-m-d H:i:s T P'), "\n";
Output
2024-01-15 07:00:00 EST -05:00

Example 2: same instant, same object

The timestamp does not change when the zone changes, and the returned value is the very same object you passed in.

Example
<?php
$date = new DateTime('2024-07-01 00:00:00', new DateTimeZone('UTC'));
$result = date_timezone_set($date, new DateTimeZone('Asia/Tokyo'));
echo json_encode([$date->getTimestamp(), $result === $date, $date->format('Y-m-d H:i T')], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
[1719792000,true,"2024-07-01 09:00 JST"]

Example 3: showing one moment in several zones

Because the function mutates its argument, clone the base object when you need several independent views of the same instant.

Example
<?php
$base = new DateTime('2024-03-31 12:00:00', new DateTimeZone('UTC'));
$out = [];
foreach (['Europe/London', 'Asia/Kolkata', 'Australia/Sydney'] as $name) {
    $copy = clone $base;
    date_timezone_set($copy, new DateTimeZone($name));
    $out[$name] = $copy->format('H:i P');
}
echo json_encode($out, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"Europe/London":"13:00 +01:00","Asia/Kolkata":"17:30 +05:30","Australia/Sydney":"23:00 +11:00"}

Edge cases

  • Daylight saving time: the offset depends on the date as well as the zone. The same zone can produce different offsets in January and July, and the formatted output reflects the rules for the object's own moment in time.
  • Fractional offsets: some zones, such as Asia/Kolkata, are offset by a half hour. Format with P or T if you need to see the offset, not just the hour.
  • Changing zone is not changing the instant: getTimestamp() returns the same value before and after the call. If you want to reinterpret the same wall-clock text in a different zone, you need to build a new object with that zone instead.
  • Offset and abbreviation zones: a DateTimeZone can also be created from an offset such as +02:00. Such a zone has a fixed offset and does not follow daylight saving rules.

Common mistakes

  1. Expecting a new object. date_timezone_set() modifies the object you give it. If other code still holds that object, it will see the new zone too. Clone first when you need to preserve the original.
  2. Passing a string. The second argument must be a DateTimeZone object, not 'Europe/Paris'. Wrap the name with new DateTimeZone('Europe/Paris').
  3. Using it with DateTimeImmutable. The procedural function is typed for DateTime. For immutable objects call the setTimezone() method, which returns a new instance and leaves the original untouched.
  4. Assuming the wall-clock time stays the same. After the call the hour and day can change, because the same instant is now described in a different zone.
  5. Relying on the default zone. Dates created without an explicit zone use the default time zone. Set it deliberately, or pass a DateTimeZone to the constructor, so results are reproducible.
  • DateTime::setTimezone(): the method form of this alias.
  • date_timezone_get(): reads the zone currently attached to an object.
  • timezone_open(): the procedural way to create a DateTimeZone.
  • date_default_timezone_set(): sets the default zone for newly created dates.
  • date_timestamp_get(): confirms that the instant is unchanged.

Recap

date_timezone_set() takes a mutable DateTime and a DateTimeZone, switches how the instant is displayed, and returns the same object. The timestamp stays fixed while the formatted fields shift. Clone the object when you need to keep the original, and use setTimezone() on immutable dates.

Tested examples

Convert a UTC time to New York time
<?php
date_default_timezone_set('UTC');
$date = new DateTime('2024-01-15 12:00:00');
date_timezone_set($date, new DateTimeZone('America/New_York'));
echo $date->format('Y-m-d H:i:s T P'), "\n";
Output
2024-01-15 07:00:00 EST -05:00
Timestamp is unchanged and the same object is returned
<?php
$date = new DateTime('2024-07-01 00:00:00', new DateTimeZone('UTC'));
$result = date_timezone_set($date, new DateTimeZone('Asia/Tokyo'));
echo json_encode([$date->getTimestamp(), $result === $date, $date->format('Y-m-d H:i T')], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
[1719792000,true,"2024-07-01 09:00 JST"]
One instant shown in several zones using clones
<?php
$base = new DateTime('2024-03-31 12:00:00', new DateTimeZone('UTC'));
$out = [];
foreach (['Europe/London', 'Asia/Kolkata', 'Australia/Sydney'] as $name) {
    $copy = clone $base;
    date_timezone_set($copy, new DateTimeZone($name));
    $out[$name] = $copy->format('H:i P');
}
echo json_encode($out, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"Europe/London":"13:00 +01:00","Asia/Kolkata":"17:30 +05:30","Australia/Sydney":"23:00 +11:00"}