Dates7 min readExamples run on PHP 8.5.10

timezone_open()

Learn how PHP timezone_open() creates a DateTimeZone object, how it fails on bad input, and how to use it safely with fixed dates.

Signature

timezone_open(string $timezone): DateTimeZone|false
Available since PHP 5.2.07.48.08.18.28.38.48.5All versions →

Purpose

timezone_open() is the procedural form of new DateTimeZone(...). The manual describes it as an alias of DateTimeZone::__construct(). You give it a timezone description and get back a DateTimeZone object. That object can be passed to DateTime, DateTimeImmutable, date_timezone_set(), timezone_offset_get() and related functions.

Use it when you write in a procedural style, or when you want a plain function call that gives you false for a bad value instead of an exception to catch.

Signature

Parameters and defaults

Parameter Type Default Meaning
$timezone string none (required) A timezone identifier such as Europe/Paris or UTC, a UTC offset such as +05:30, or a timezone abbreviation such as EST.

There are no optional parameters. The function does not read or change the default timezone set by date_default_timezone_set(); it only builds an object for the value you pass.

Return value and failure cases

On success you get a DateTimeZone object. If the string is not a recognized timezone, the procedural function returns false and raises a warning. Empty strings and made-up names such as Mars/Base are failures. Always compare the result with false before you use it as an object.

The object-oriented constructor behaves differently. new DateTimeZone('Mars/Base') throws an exception rather than returning false.

Example 1: create a zone and convert a time

The fixed UTC input makes the result deterministic. The zone is created once, then used for the conversion and for an offset lookup.

Example
<?php
$utc = new DateTimeImmutable('2024-01-15 12:00:00', timezone_open('UTC'));
$tokyo = timezone_open('Asia/Tokyo');
$local = $utc->setTimezone($tokyo);
echo json_encode([
    'zone' => timezone_name_get($tokyo),
    'local' => $local->format('Y-m-d H:i:s P'),
    'offset' => timezone_offset_get($tokyo, $utc),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"zone":"Asia/Tokyo","local":"2024-01-15 21:00:00 +09:00","offset":32400}

The offset is returned in seconds east of UTC, so Tokyo is 32400, which is nine hours.

Example 2: named zones versus fixed offsets

A region identifier carries daylight saving rules, so its offset depends on the date. A fixed offset string always has the same offset.

Example
<?php
$london = timezone_open('Europe/London');
$winter = new DateTimeImmutable('2024-01-15 12:00:00', timezone_open('UTC'));
$summer = new DateTimeImmutable('2024-07-15 12:00:00', timezone_open('UTC'));
$fixed = timezone_open('+05:30');
echo json_encode([
    'londonWinter' => timezone_offset_get($london, $winter),
    'londonSummer' => timezone_offset_get($london, $summer),
    'fixedName' => timezone_name_get($fixed),
    'fixedOffset' => timezone_offset_get($fixed, $summer),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"londonWinter":0,"londonSummer":3600,"fixedName":"+05:30","fixedOffset":19800}

London is at offset 0 in January and 3600 in July. The +05:30 zone stays at 19800 in both seasons.

Example 3: validate user-supplied names

When a timezone name comes from a form or a stored setting, wrap the call in a small helper that turns failure into null. The @ operator silences the warning here because the helper reports failure through its return value. Use it narrowly, only around the call you are handling.

Example
<?php
function zoneOrNull(string $name): ?DateTimeZone
{
    $zone = @timezone_open($name);
    return $zone === false ? null : $zone;
}

$names = ['Europe/London', 'Mars/Base'];
$result = [];
foreach ($names as $name) {
    $result[$name] = zoneOrNull($name) !== null;
}
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"Europe/London":true,"Mars/Base":false}

Edge cases

  • A timezone object is not a moment in time. It describes rules, so you need a date to learn the actual offset.
  • Offsets such as +05:30 are accepted, but they have no daylight saving rules. A real region identifier is usually better for scheduling future events.
  • Abbreviations such as EST are accepted as timezone values, but they are less precise than region identifiers because one abbreviation can be used in several places.
  • Passing UTC is the clearest way to request Coordinated Universal Time.
  • Creating a zone object does not change date() or the default timezone for the script.

Common mistakes

  1. Not checking for false. Passing the result straight into code that expects DateTimeZone fails with a type error.
  2. Inventing identifiers. Use names such as America/New_York, not city nicknames or country names.
  3. Expecting a fixed offset from a region. Region zones change offsets across the year.
  4. Hiding all warnings globally. Validate input and handle false explicitly rather than suppressing errors across a whole script.
  5. Confusing it with date_default_timezone_set(). That function changes the default for later date calls. timezone_open() only returns an object.
  • timezone_name_get() reads the name of a zone object.
  • timezone_offset_get() returns the offset for a specific date.
  • date_timezone_set() changes the zone of an existing date object.
  • date_default_timezone_set() sets the script default.
  • DateTimeZone::listIdentifiers() lists valid region identifiers.

Recap

timezone_open(string $timezone) builds a DateTimeZone from an identifier, offset or abbreviation and returns false with a warning when the value is not valid. It is an alias of DateTimeZone::__construct(), so the two accept the same input, but the function form reports failure through its return value. Check the return value, prefer region identifiers for real-world schedules, and ask for offsets using a concrete date.

Tested examples

Create a zone and convert a fixed UTC time
<?php
$utc = new DateTimeImmutable('2024-01-15 12:00:00', timezone_open('UTC'));
$tokyo = timezone_open('Asia/Tokyo');
$local = $utc->setTimezone($tokyo);
echo json_encode([
    'zone' => timezone_name_get($tokyo),
    'local' => $local->format('Y-m-d H:i:s P'),
    'offset' => timezone_offset_get($tokyo, $utc),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"zone":"Asia/Tokyo","local":"2024-01-15 21:00:00 +09:00","offset":32400}
Named zones versus fixed offsets
<?php
$london = timezone_open('Europe/London');
$winter = new DateTimeImmutable('2024-01-15 12:00:00', timezone_open('UTC'));
$summer = new DateTimeImmutable('2024-07-15 12:00:00', timezone_open('UTC'));
$fixed = timezone_open('+05:30');
echo json_encode([
    'londonWinter' => timezone_offset_get($london, $winter),
    'londonSummer' => timezone_offset_get($london, $summer),
    'fixedName' => timezone_name_get($fixed),
    'fixedOffset' => timezone_offset_get($fixed, $summer),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"londonWinter":0,"londonSummer":3600,"fixedName":"+05:30","fixedOffset":19800}
Validate user-supplied timezone names
<?php
function zoneOrNull(string $name): ?DateTimeZone
{
    $zone = @timezone_open($name);
    return $zone === false ? null : $zone;
}

$names = ['Europe/London', 'Mars/Base'];
$result = [];
foreach ($names as $name) {
    $result[$name] = zoneOrNull($name) !== null;
}
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"Europe/London":true,"Mars/Base":false}