Dates7 min readExamples run on PHP 8.5.10

timezone_identifiers_list()

Learn how timezone_identifiers_list() returns PHP's known time zone identifiers, how to filter them by group or country, and which mistakes to avoid.

Signature

timezone_identifiers_list(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null): array
Available since PHP 5.2.07.48.08.18.28.38.48.5All versions →

Purpose

timezone_identifiers_list() returns the time zone identifiers that PHP knows about, such as UTC, Europe/Paris or Asia/Tokyo. You typically use it to build a time zone dropdown, to check that a stored identifier is valid, or to narrow choices to one region or country.

The function is a procedural alias of DateTimeZone::listIdentifiers(). Both behave the same way, so pick the style that fits the rest of your code.

Signature

Parameters and defaults

  • $timezoneGroup selects which identifiers to return. The default is DateTimeZone::ALL. The class constants include the regional groups AFRICA, AMERICA, ANTARCTICA, ARCTIC, ASIA, ATLANTIC, AUSTRALIA, EUROPE, INDIAN and PACIFIC. They also include UTC, ALL, ALL_WITH_BC and PER_COUNTRY. Regional groups are bit flags, so they can be combined with |.
  • $countryCode is only meaningful with DateTimeZone::PER_COUNTRY. It is a two-letter ISO 3166-1 country code such as JP or NZ. With any other group it is ignored. The default is null.

Return value and failure cases

The function returns a list array of strings. Each element is an identifier. An unrecognised group value gives no useful identifiers, so stick to the class constants.

If you use DateTimeZone::PER_COUNTRY with a missing or malformed country code, PHP 8 raises a ValueError instead of quietly returning something. A well-formed code that has no zones yields an empty array.

The contents of the list depend on the time zone database bundled with your PHP build. Zones may be added or renamed between releases, so avoid hard-coding the total number of identifiers.

Example 1: the UTC group

The UTC group is the smallest possible filter. It contains just the one identifier.

Example
<?php
$zones = timezone_identifiers_list(DateTimeZone::UTC);
echo json_encode($zones, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["UTC"]

Example 2: zones for one country

Combine PER_COUNTRY with a country code to list the zones used there. Japan uses a single zone.

Example
<?php
$zones = timezone_identifiers_list(DateTimeZone::PER_COUNTRY, 'JP');
echo json_encode($zones, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["Asia/Tokyo"]

Example 3: validating a submitted identifier

A common use is checking user input against the known list. Use strict comparison, and remember that matching is case-sensitive.

Example
<?php
function isListedZone(string $id): bool
{
    return in_array($id, timezone_identifiers_list(), true);
}

$result = [
    'Europe/Paris' => isListedZone('Europe/Paris'),
    'europe/paris' => isListedZone('europe/paris'),
    'Mars/Base' => isListedZone('Mars/Base'),
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"Europe/Paris":true,"europe/paris":false,"Mars/Base":false}

Edge cases

  • Case sensitivity. The list contains canonical spellings. europe/paris is not in the array, even though some PHP date APIs may be more forgiving when constructing a zone.
  • Backward-compatible names. DateTimeZone::ALL does not include legacy aliases. Use DateTimeZone::ALL_WITH_BC if you must recognise those older names.
  • Country code is ignored without PER_COUNTRY. Passing 'JP' together with DateTimeZone::ASIA still returns every Asian zone.
  • Abbreviations are not identifiers. Values such as EST or CEST are abbreviations. Identifiers use the Area/Location form, except for entries like UTC.
  • Order and size. Do not depend on the number of entries or on a specific position. Look values up instead.

Common mistakes

  1. Passing a country code without DateTimeZone::PER_COUNTRY and expecting filtering.
  2. Using loose in_array() without the strict flag. It works on strings here, but strict comparison is a safer habit.
  3. Hard-coding a count of zones in tests. The count depends on the bundled database.
  4. Treating the list as a list of offsets. It has names only. Create a DateTimeZone object and ask for offsets at a specific moment if you need them.
  5. Calling the function repeatedly inside a loop. Store the result in a variable or a array_flip() lookup table when you validate many values.
  • DateTimeZone::listIdentifiers(), the method this function aliases
  • timezone_abbreviations_list() for abbreviation data
  • timezone_open() and DateTimeZone::__construct() for creating a zone object
  • date_default_timezone_set() for choosing the default zone

Recap

timezone_identifiers_list() returns an array of time zone identifier strings, optionally filtered by group or by country with PER_COUNTRY. It is an alias of DateTimeZone::listIdentifiers(). Treat its contents as data from the bundled database, compare names exactly, and never assume a fixed size.

Tested examples

The UTC group
<?php
$zones = timezone_identifiers_list(DateTimeZone::UTC);
echo json_encode($zones, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["UTC"]
Zones for one country
<?php
$zones = timezone_identifiers_list(DateTimeZone::PER_COUNTRY, 'JP');
echo json_encode($zones, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["Asia/Tokyo"]
Validating a submitted identifier
<?php
function isListedZone(string $id): bool
{
    return in_array($id, timezone_identifiers_list(), true);
}

$result = [
    'Europe/Paris' => isListedZone('Europe/Paris'),
    'europe/paris' => isListedZone('europe/paris'),
    'Mars/Base' => isListedZone('Mars/Base'),
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"Europe/Paris":true,"europe/paris":false,"Mars/Base":false}