Dates7 min readExamples run on PHP 8.5.10

timezone_offset_get()

Learn how timezone_offset_get() returns a time zone's UTC offset in seconds for a given moment, with DST examples, edge cases and common mistakes.

Signature

timezone_offset_get(DateTimeZone $object, DateTimeInterface $datetime): int
Available since PHP 5.2.07.48.08.18.28.38.48.5All versions →

Purpose

timezone_offset_get() tells you how many seconds a time zone is ahead of or behind UTC at a particular moment. It is the procedural alias of DateTimeZone::getOffset(), so both forms give the same result. Pick whichever matches your code style.

The offset depends on the moment you ask about. Many zones change offset when daylight saving time starts or ends, and the second argument supplies the instant to evaluate.

Signature

Parameters

  • $object: the DateTimeZone whose offset you want. It can be a named region such as Europe/Paris, a fixed offset such as +05:45, or UTC. It is required and has no default.
  • $datetime: any DateTimeInterface object, such as DateTime or DateTimeImmutable. Only the instant it represents is used. The time zone attached to this object does not change the answer, because you are asking about $object. It is required and has no default.

Return value and failures

The function returns an int: the offset from UTC in seconds. Positive values are east of UTC (for example 3600 for UTC+01:00) and negative values are west (for example -18000 for UTC-05:00).

There is no false return to check. Failures surface as exceptions or errors instead. An invalid zone name makes the DateTimeZone constructor throw before you reach this function. Passing arguments of the wrong type, such as a string where a DateTimeZone is expected, throws a TypeError.

Example 1: the same zone in winter and summer

Paris is UTC+01:00 in January and UTC+02:00 in July. The same zone object returns a different offset depending on the date you pass.

Example
<?php
date_default_timezone_set('UTC');
$tz = new DateTimeZone('Europe/Paris');
$winter = new DateTimeImmutable('2024-01-15 12:00:00', new DateTimeZone('UTC'));
$summer = new DateTimeImmutable('2024-07-15 12:00:00', new DateTimeZone('UTC'));
echo json_encode([timezone_offset_get($tz, $winter), timezone_offset_get($tz, $summer)]), "\n";
Output
[3600,7200]

Example 2: comparing several zones

One reference date can be used to compare different kinds of zones, including a fixed-offset zone. Fixed offsets and UTC return the same value for any date.

Example
<?php
date_default_timezone_set('UTC');
$date = new DateTime('2024-03-01 00:00:00');
$zones = ['Asia/Kolkata', 'America/New_York', 'UTC', '+05:45'];
$result = [];
foreach ($zones as $name) {
    $result[$name] = timezone_offset_get(new DateTimeZone($name), $date);
}
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"Asia/Kolkata":19800,"America/New_York":-18000,"UTC":0,"+05:45":20700}

Example 3: a daylight saving boundary

In 2024, New York switched to daylight saving time at 07:00:00 UTC on 10 March. One second earlier the offset is -18000. At the switch it becomes -14400. The last value shows the alias matches the method form.

Example
<?php
date_default_timezone_set('UTC');
$tz = new DateTimeZone('America/New_York');
$utc = new DateTimeZone('UTC');
$before = new DateTimeImmutable('2024-03-10 06:59:59', $utc);
$after = new DateTimeImmutable('2024-03-10 07:00:00', $utc);
echo json_encode([
    'before' => timezone_offset_get($tz, $before),
    'after' => timezone_offset_get($tz, $after),
    'same' => $tz->getOffset($after) === timezone_offset_get($tz, $after),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"before":-18000,"after":-14400,"same":true}

Edge cases

  • Transitions: the answer is based on the exact instant. One second can separate two different offsets, as in Example 3.
  • Fixed offsets: a zone created from +05:45 always reports 20700, whatever date you pass.
  • The datetime's own zone: two objects representing the same instant but carrying different zones give identical results, because only the instant matters.
  • Half-hour and 45-minute zones: offsets are not always whole hours. India is 19800 and Nepal is 20700, so never assume a multiple of 3600.
  • Historic dates: region zones can have had different offsets in the past. The result follows the time zone database bundled with your PHP build.

Common mistakes

  1. Expecting hours. The result is in seconds. Divide by 3600 if you need hours, and keep fractional hours in mind.
  2. Forgetting the date matters. Using "now" or an arbitrary date for a region zone can yield the wrong offset for the date you really care about.
  3. Confusing the two arguments. The first argument is the zone you are measuring. Putting a zone on the DateTime and expecting it to be measured does not work.
  4. Reversing the sign. A positive number means the zone is ahead of UTC. Some other systems use the opposite convention, so check before mixing values.
  5. Hard-coding a single offset per zone. Storing -18000 for New York breaks as soon as daylight saving time applies.
  6. Looking for a failure value. Do not test for false. Catch exceptions where you build the zone from user input.
  • DateTimeZone::getOffset(): the method form of this function.
  • timezone_open(): creates a DateTimeZone procedurally.
  • timezone_name_get(): returns the zone's name.
  • timezone_transitions_get(): lists offset changes for a zone.
  • date_offset_get(): returns the offset of a DateTime object's own zone.

Recap

timezone_offset_get($zone, $datetime) returns the UTC offset in seconds of $zone at the instant given by $datetime. It is an alias of DateTimeZone::getOffset(), gives positive values east of UTC, and reflects daylight saving rules for region zones. Always pass the date you actually care about, and remember the result is in seconds.

Tested examples

The same zone in winter and summer
<?php
date_default_timezone_set('UTC');
$tz = new DateTimeZone('Europe/Paris');
$winter = new DateTimeImmutable('2024-01-15 12:00:00', new DateTimeZone('UTC'));
$summer = new DateTimeImmutable('2024-07-15 12:00:00', new DateTimeZone('UTC'));
echo json_encode([timezone_offset_get($tz, $winter), timezone_offset_get($tz, $summer)]), "\n";
Output
[3600,7200]
Comparing several zones
<?php
date_default_timezone_set('UTC');
$date = new DateTime('2024-03-01 00:00:00');
$zones = ['Asia/Kolkata', 'America/New_York', 'UTC', '+05:45'];
$result = [];
foreach ($zones as $name) {
    $result[$name] = timezone_offset_get(new DateTimeZone($name), $date);
}
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"Asia/Kolkata":19800,"America/New_York":-18000,"UTC":0,"+05:45":20700}
A daylight saving boundary
<?php
date_default_timezone_set('UTC');
$tz = new DateTimeZone('America/New_York');
$utc = new DateTimeZone('UTC');
$before = new DateTimeImmutable('2024-03-10 06:59:59', $utc);
$after = new DateTimeImmutable('2024-03-10 07:00:00', $utc);
echo json_encode([
    'before' => timezone_offset_get($tz, $before),
    'after' => timezone_offset_get($tz, $after),
    'same' => $tz->getOffset($after) === timezone_offset_get($tz, $after),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"before":-18000,"after":-14400,"same":true}