Gerando uma lista suspensa de fusos horários com PHP


141

A maioria dos sites precisa de alguma maneira de mostrar as datas no site no fuso horário preferido dos usuários. Abaixo estão duas listas que eu encontrei e, em seguida, um método usando a classe DateTime embutida no PHP 5.

Preciso de ajuda para saber qual desses seria o melhor tentar usar ao tentar obter o deslocamento UTC do usuário no registro.

1:

<option value="-12">[UTC - 12] Baker Island Time</option>
<option value="-11">[UTC - 11] Niue Time, Samoa Standard Time</option>
<option value="-10">[UTC - 10] Hawaii-Aleutian Standard Time, Cook Island Time</option>
<option value="-9.5">[UTC - 9:30] Marquesas Islands Time</option>
<option value="-9">[UTC - 9] Alaska Standard Time, Gambier Island Time</option>
<option value="-8">[UTC - 8] Pacific Standard Time</option>
<option value="-7">[UTC - 7] Mountain Standard Time</option>
<option value="-6">[UTC - 6] Central Standard Time</option>
<option value="-5">[UTC - 5] Eastern Standard Time</option>
<option value="-4.5">[UTC - 4:30] Venezuelan Standard Time</option>
<option value="-4">[UTC - 4] Atlantic Standard Time</option>
<option value="-3.5">[UTC - 3:30] Newfoundland Standard Time</option>
<option value="-3">[UTC - 3] Amazon Standard Time, Central Greenland Time</option>
<option value="-2">[UTC - 2] Fernando de Noronha Time, South Georgia &amp; the South Sandwich Islands Time</option>
<option value="-1">[UTC - 1] Azores Standard Time, Cape Verde Time, Eastern Greenland Time</option>
<option value="0" selected="selected">[UTC] Western European Time, Greenwich Mean Time</option>
<option value="1">[UTC + 1] Central European Time, West African Time</option>
<option value="2">[UTC + 2] Eastern European Time, Central African Time</option>
<option value="3">[UTC + 3] Moscow Standard Time, Eastern African Time</option>
<option value="3.5">[UTC + 3:30] Iran Standard Time</option>
<option value="4">[UTC + 4] Gulf Standard Time, Samara Standard Time</option>
<option value="4.5">[UTC + 4:30] Afghanistan Time</option>
<option value="5">[UTC + 5] Pakistan Standard Time, Yekaterinburg Standard Time</option>
<option value="5.5">[UTC + 5:30] Indian Standard Time, Sri Lanka Time</option>
<option value="5.75">[UTC + 5:45] Nepal Time</option>
<option value="6">[UTC + 6] Bangladesh Time, Bhutan Time, Novosibirsk Standard Time</option>
<option value="6.5">[UTC + 6:30] Cocos Islands Time, Myanmar Time</option>
<option value="7">[UTC + 7] Indochina Time, Krasnoyarsk Standard Time</option>
<option value="8">[UTC + 8] Chinese Standard Time, Australian Western Standard Time, Irkutsk Standard Time</option>
<option value="8.75">[UTC + 8:45] Southeastern Western Australia Standard Time</option>
<option value="9">[UTC + 9] Japan Standard Time, Korea Standard Time, Chita Standard Time</option>
<option value="9.5">[UTC + 9:30] Australian Central Standard Time</option>
<option value="10">[UTC + 10] Australian Eastern Standard Time, Vladivostok Standard Time</option>
<option value="10.5">[UTC + 10:30] Lord Howe Standard Time</option>
<option value="11">[UTC + 11] Solomon Island Time, Magadan Standard Time</option>
<option value="11.5">[UTC + 11:30] Norfolk Island Time</option>
<option value="12">[UTC + 12] New Zealand Time, Fiji Time, Kamchatka Standard Time</option>
<option value="12.75">[UTC + 12:45] Chatham Islands Time</option>
<option value="13">[UTC + 13] Tonga Time, Phoenix Islands Time</option>
<option value="14">[UTC + 14] Line Island Time</option>

Ou usando valores compatíveis com PHP:

<option value="Pacific/Midway">(GMT-11:00) Midway Island, Samoa</option>
<option value="America/Adak">(GMT-10:00) Hawaii-Aleutian</option>
<option value="Etc/GMT+10">(GMT-10:00) Hawaii</option>
<option value="Pacific/Marquesas">(GMT-09:30) Marquesas Islands</option>
<option value="Pacific/Gambier">(GMT-09:00) Gambier Islands</option>
<option value="America/Anchorage">(GMT-09:00) Alaska</option>
<option value="America/Ensenada">(GMT-08:00) Tijuana, Baja California</option>
<option value="Etc/GMT+8">(GMT-08:00) Pitcairn Islands</option>
<option value="America/Los_Angeles">(GMT-08:00) Pacific Time (US & Canada)</option>
<option value="America/Denver">(GMT-07:00) Mountain Time (US & Canada)</option>
<option value="America/Chihuahua">(GMT-07:00) Chihuahua, La Paz, Mazatlan</option>
<option value="America/Dawson_Creek">(GMT-07:00) Arizona</option>
<option value="America/Belize">(GMT-06:00) Saskatchewan, Central America</option>
<option value="America/Cancun">(GMT-06:00) Guadalajara, Mexico City, Monterrey</option>
<option value="Chile/EasterIsland">(GMT-06:00) Easter Island</option>
<option value="America/Chicago">(GMT-06:00) Central Time (US & Canada)</option>
<option value="America/New_York">(GMT-05:00) Eastern Time (US & Canada)</option>
<option value="America/Havana">(GMT-05:00) Cuba</option>
<option value="America/Bogota">(GMT-05:00) Bogota, Lima, Quito, Rio Branco</option>
<option value="America/Caracas">(GMT-04:30) Caracas</option>
<option value="America/Santiago">(GMT-04:00) Santiago</option>
<option value="America/La_Paz">(GMT-04:00) La Paz</option>
<option value="Atlantic/Stanley">(GMT-04:00) Faukland Islands</option>
<option value="America/Campo_Grande">(GMT-04:00) Brazil</option>
<option value="America/Goose_Bay">(GMT-04:00) Atlantic Time (Goose Bay)</option>
<option value="America/Glace_Bay">(GMT-04:00) Atlantic Time (Canada)</option>
<option value="America/St_Johns">(GMT-03:30) Newfoundland</option>
<option value="America/Araguaina">(GMT-03:00) UTC-3</option>
<option value="America/Montevideo">(GMT-03:00) Montevideo</option>
<option value="America/Miquelon">(GMT-03:00) Miquelon, St. Pierre</option>
<option value="America/Godthab">(GMT-03:00) Greenland</option>
<option value="America/Argentina/Buenos_Aires">(GMT-03:00) Buenos Aires</option>
<option value="America/Sao_Paulo">(GMT-03:00) Brasilia</option>
<option value="America/Noronha">(GMT-02:00) Mid-Atlantic</option>
<option value="Atlantic/Cape_Verde">(GMT-01:00) Cape Verde Is.</option>
<option value="Atlantic/Azores">(GMT-01:00) Azores</option>
<option value="Europe/Belfast">(GMT) Greenwich Mean Time : Belfast</option>
<option value="Europe/Dublin">(GMT) Greenwich Mean Time : Dublin</option>
<option value="Europe/Lisbon">(GMT) Greenwich Mean Time : Lisbon</option>
<option value="Europe/London">(GMT) Greenwich Mean Time : London</option>
<option value="Africa/Abidjan">(GMT) Monrovia, Reykjavik</option>
<option value="Europe/Amsterdam">(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna</option>
<option value="Europe/Belgrade">(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague</option>
<option value="Europe/Brussels">(GMT+01:00) Brussels, Copenhagen, Madrid, Paris</option>
<option value="Africa/Algiers">(GMT+01:00) West Central Africa</option>
<option value="Africa/Windhoek">(GMT+01:00) Windhoek</option>
<option value="Asia/Beirut">(GMT+02:00) Beirut</option>
<option value="Africa/Cairo">(GMT+02:00) Cairo</option>
<option value="Asia/Gaza">(GMT+02:00) Gaza</option>
<option value="Africa/Blantyre">(GMT+02:00) Harare, Pretoria</option>
<option value="Asia/Jerusalem">(GMT+02:00) Jerusalem</option>
<option value="Europe/Minsk">(GMT+02:00) Minsk</option>
<option value="Asia/Damascus">(GMT+02:00) Syria</option>
<option value="Europe/Moscow">(GMT+03:00) Moscow, St. Petersburg, Volgograd</option>
<option value="Africa/Addis_Ababa">(GMT+03:00) Nairobi</option>
<option value="Asia/Tehran">(GMT+03:30) Tehran</option>
<option value="Asia/Dubai">(GMT+04:00) Abu Dhabi, Muscat</option>
<option value="Asia/Yerevan">(GMT+04:00) Yerevan</option>
<option value="Asia/Kabul">(GMT+04:30) Kabul</option>
<option value="Asia/Yekaterinburg">(GMT+05:00) Ekaterinburg</option>
<option value="Asia/Tashkent">(GMT+05:00) Tashkent</option>
<option value="Asia/Kolkata">(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi</option>
<option value="Asia/Katmandu">(GMT+05:45) Kathmandu</option>
<option value="Asia/Dhaka">(GMT+06:00) Astana, Dhaka</option>
<option value="Asia/Novosibirsk">(GMT+06:00) Novosibirsk</option>
<option value="Asia/Rangoon">(GMT+06:30) Yangon (Rangoon)</option>
<option value="Asia/Bangkok">(GMT+07:00) Bangkok, Hanoi, Jakarta</option>
<option value="Asia/Krasnoyarsk">(GMT+07:00) Krasnoyarsk</option>
<option value="Asia/Hong_Kong">(GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi</option>
<option value="Asia/Irkutsk">(GMT+08:00) Irkutsk, Ulaan Bataar</option>
<option value="Australia/Perth">(GMT+08:00) Perth</option>
<option value="Australia/Eucla">(GMT+08:45) Eucla</option>
<option value="Asia/Tokyo">(GMT+09:00) Osaka, Sapporo, Tokyo</option>
<option value="Asia/Seoul">(GMT+09:00) Seoul</option>
<option value="Asia/Yakutsk">(GMT+09:00) Yakutsk</option>
<option value="Australia/Adelaide">(GMT+09:30) Adelaide</option>
<option value="Australia/Darwin">(GMT+09:30) Darwin</option>
<option value="Australia/Brisbane">(GMT+10:00) Brisbane</option>
<option value="Australia/Hobart">(GMT+10:00) Hobart</option>
<option value="Asia/Vladivostok">(GMT+10:00) Vladivostok</option>
<option value="Australia/Lord_Howe">(GMT+10:30) Lord Howe Island</option>
<option value="Etc/GMT-11">(GMT+11:00) Solomon Is., New Caledonia</option>
<option value="Asia/Magadan">(GMT+11:00) Magadan</option>
<option value="Pacific/Norfolk">(GMT+11:30) Norfolk Island</option>
<option value="Asia/Anadyr">(GMT+12:00) Anadyr, Kamchatka</option>
<option value="Pacific/Auckland">(GMT+12:00) Auckland, Wellington</option>
<option value="Etc/GMT-12">(GMT+12:00) Fiji, Kamchatka, Marshall Is.</option>
<option value="Pacific/Chatham">(GMT+12:45) Chatham Islands</option>
<option value="Pacific/Tongatapu">(GMT+13:00) Nuku'alofa</option>
<option value="Pacific/Kiritimati">(GMT+14:00) Kiritimati</option>

Ou apenas usando o próprio PHP:

$timezones = DateTimeZone::listAbbreviations();

$cities = array();
foreach( $timezones as $key => $zones )
{
    foreach( $zones as $id => $zone )
    {
        /**
         * Only get timezones explicitely not part of "Others".
         * @see http://www.php.net/manual/en/timezones.others.php
         */
        if ( preg_match( '/^(America|Antartica|Arctic|Asia|Atlantic|Europe|Indian|Pacific)\//', $zone['timezone_id'] ) 
            && $zone['timezone_id']) {
            $cities[$zone['timezone_id']][] = $key;
        }
    }
}

// For each city, have a comma separated list of all possible timezones for that city.
foreach( $cities as $key => $value )
    $cities[$key] = join( ', ', $value);

// Only keep one city (the first and also most important) for each set of possibilities. 
$cities = array_unique( $cities );

// Sort by area/city name.
ksort( $cities );

Parece que o último seria o mais seguro, pois aumentaria com o lançamento do PHP. Você também pode inverter essa matriz quando necessário para vincular fusos horários a nomes de cidades.


1
Comentário inútil, mas como residente de Saskatchewan, eu preferiria ler: <option value = "America / Regina"> (GMT-06: 00) Saskatchewan, América Central </option> not <option value = "America / Belize "> (GMT-06: 00) Saskatchewan, América Central </option> :)
Kenton de Jong

Em termos de interface do usuário, sugiro colocar uma cópia dos valores que o usuário provavelmente usará (com base no seu público-alvo e / ou na detecção do navegador) no topo da lista, pois a lista pode contar até centenas de valores.
Fabien Snauwaert

Respostas:


181

Eu faria isso em PHP, exceto que evitaria fazer o preg_match 100 algumas vezes e faria isso para gerar sua lista.

$tzlist = DateTimeZone::listIdentifiers(DateTimeZone::ALL);

Além disso, eu usaria os nomes do PHP para os 'fusos horários' e esqueceria as compensações GMT, que serão alteradas com base no horário de verão. Um código assim no phpbb é apenas dessa forma porque eles ainda suportam o PHP4 e não podem confiar nos objetos DateTime ou DateTimeZone que estão lá.


5
Estou usando o PHP 5.2.5 Undefined class constant 'AFRICA'quando tento usar a classe DateTimeZone. Eu verifiquei as classes definidas e ele está listado, então talvez o Windows precise de algo mais para que isso funcione.
Xeoncross

Fui informado de um bug pelo mesmo erro que o Xeoncross e queria saber se alguém sabe como isso é possível? O manual parece indicar que essas constantes estão disponíveis desde o PHP5.2, mas isso está incorreto?
Br11

2
Desculpe comentar duas vezes, mas não consigo editar o anterior. Apenas para esclarecer, parece que o problema aqui é que o parâmetro $ what do listIdentifiers foi adicionado apenas no PHP5.3. Parece que também foi quando as constantes foram adicionadas, mas ainda não consigo encontrar nenhuma referência no guia de migração para 5.3 ou em qualquer log de alterações 5.3.x para fazer backup disso.
brendo

@ brendo: Estou com a mesma impressão, pois $regionso valor 1023substituiria todas essas constantes. Além disso, se você precisar de expressões regulares, considere em preg_grep()vez de preg_match().
Alix Axel

2
Atualizei para usar em DateTimeZone::ALLvez de criar uma matriz de regiões disponíveis e fazer um loop por ela.
Nathan JB

73

Seguindo o exemplo de user210179 acima, escrevi a seguinte função para gerar uma lista de todos os fusos horários com seus desvios:

function generate_timezone_list()
{
    static $regions = array(
        DateTimeZone::AFRICA,
        DateTimeZone::AMERICA,
        DateTimeZone::ANTARCTICA,
        DateTimeZone::ASIA,
        DateTimeZone::ATLANTIC,
        DateTimeZone::AUSTRALIA,
        DateTimeZone::EUROPE,
        DateTimeZone::INDIAN,
        DateTimeZone::PACIFIC,
    );

    $timezones = array();
    foreach( $regions as $region )
    {
        $timezones = array_merge( $timezones, DateTimeZone::listIdentifiers( $region ) );
    }

    $timezone_offsets = array();
    foreach( $timezones as $timezone )
    {
        $tz = new DateTimeZone($timezone);
        $timezone_offsets[$timezone] = $tz->getOffset(new DateTime);
    }

    // sort timezone by offset
    asort($timezone_offsets);

    $timezone_list = array();
    foreach( $timezone_offsets as $timezone => $offset )
    {
        $offset_prefix = $offset < 0 ? '-' : '+';
        $offset_formatted = gmdate( 'H:i', abs($offset) );

        $pretty_offset = "UTC${offset_prefix}${offset_formatted}";

        $timezone_list[$timezone] = "(${pretty_offset}) $timezone";
    }

    return $timezone_list;
}

Isso irá gerar uma matriz parecida com:

[Pacific/Midway] => (UTC-11:00) Pacific/Midway
[Pacific/Pago_Pago] => (UTC-11:00) Pacific/Pago_Pago
[Pacific/Niue] => (UTC-11:00) Pacific/Niue
[Pacific/Honolulu] => (UTC-10:00) Pacific/Honolulu
[Pacific/Fakaofo] => (UTC-10:00) Pacific/Fakaofo

Atualmente, ele é classificado por deslocamentos, mas você pode classificar facilmente pelo nome do fuso horário executando um em ksort()vez de asort().


6
Em vez de gerar a matriz de regiões e iterar através delas, parece que agora você pode simplesmente ligar. $timezones = DateTimeZone::listIdentifiers( DateTimeZone::ALL );Se você quiser incluir apenas determinadas regiões, pode ligar.$timezones = DateTimeZone::listIdentifiers( DateTimeZone::AMERICA | DateTimeZone::EUROPE );
Toland Hon

@ Nathan É possível classificar a lista pelo valor do deslocamento, em vez do texto do deslocamento. Quero dizer, em vez de UTC-11.00,UTC-10.00, ... ,UTC-01.00,UTC+14.00,UTC-13.00, ... ,UTC+00.00, quero classificá-los comoUTC-11.00,UTC-10.00, ... ,UTC-01.00,UTC+00.00,UTC+01.00, ... ,UTC+13.00,UTC-14.00
Taufik Nurrohman 11/02

Fiz literalmente uma alteração nisso, consegui substituir os sublinhados por espaços nos valores, além disso, perfeição, obrigado!
James Hunt

array_mergenão deve ser usado em um loop.
bobina

Bom código, inspirou uma classe que eu tenho código-fonte aberto aqui: github.com/peterjtracey/timezoneWidget/blob/master/server/php/…
Peter Tracey

43

Apesar do número de respostas existentes, eu fiz outra solução para esse problema. Os profissionais da minha implementação são:

  • A lista de fusos horários é gerada dinamicamente e, portanto, é atualizada automaticamente quando os fusos horários podem mudar (em PHP).
  • Os nomes de fuso horário são prettificados. Por exemplo, "America / St_Barthelemy" se torna "America, St. Barthelemy".
  • Os fusos horários são classificados em deslocamento e nome. A resposta de Toland classifica apenas no deslocamento, resultando em grupos de fusos horários não classificados no mesmo deslocamento.
  • As informações de deslocamento não são recuperadas DateTimeZone::listAbbreviations, pois esse método também retorna informações históricas do fuso horário . A resposta de Favio usa esse método, que resulta em compensações incorretas (históricas)
  • A lista de fusos horários é gerada apenas quando solicitada pela primeira vez (e 'armazenada em cache' usando uma variável estática).

Aqui está o código completo:

function timezone_list() {
    static $timezones = null;

    if ($timezones === null) {
        $timezones = [];
        $offsets = [];
        $now = new DateTime('now', new DateTimeZone('UTC'));

        foreach (DateTimeZone::listIdentifiers() as $timezone) {
            $now->setTimezone(new DateTimeZone($timezone));
            $offsets[] = $offset = $now->getOffset();
            $timezones[$timezone] = '(' . format_GMT_offset($offset) . ') ' . format_timezone_name($timezone);
        }

        array_multisort($offsets, $timezones);
    }

    return $timezones;
}

function format_GMT_offset($offset) {
    $hours = intval($offset / 3600);
    $minutes = abs(intval($offset % 3600 / 60));
    return 'GMT' . ($offset ? sprintf('%+03d:%02d', $hours, $minutes) : '');
}

function format_timezone_name($name) {
    $name = str_replace('/', ', ', $name);
    $name = str_replace('_', ' ', $name);
    $name = str_replace('St ', 'St. ', $name);
    return $name;
}

E aqui está um exemplo da saída

Array
(
    [Pacific/Midway]    => (GMT-11:00) Pacific, Midway
    [Pacific/Niue]      => (GMT-11:00) Pacific, Niue
    [Pacific/Pago_Pago] => (GMT-11:00) Pacific, Pago Pago
    [America/Adak]      => (GMT-10:00) America, Adak
    [Pacific/Honolulu]  => (GMT-10:00) Pacific, Honolulu
    [Pacific/Johnston]  => (GMT-10:00) Pacific, Johnston
    [Pacific/Rarotonga] => (GMT-10:00) Pacific, Rarotonga
    [Pacific/Tahiti]    => (GMT-10:00) Pacific, Tahiti
    [Pacific/Marquesas] => (GMT-09:30) Pacific, Marquesas
    [America/Anchorage] => (GMT-09:00) America, Anchorage
    ...
)

Sei que esse comentário ocorre alguns anos após o último, mas estou tentando implementar seu código como a função principal no lugar disso - github.com/DocWatson/acf-timezone-picker/blob/master/… - começando às line 73. Eu sei que não pode ser muito difícil de alcançar, mas simplesmente não consigo descobrir onde estou aquém. Qualquer pensamento seria muito apreciado!
DaveyJake

1
@DaveyJake Coloquei minhas funções em sua classe, isso funciona para você? gist.github.com/jhogervorst/e284f01a960f8ff99b7e8dbf5b11b89a
Jonathan

Isso funcionou, mas eu tive que mudar suas duas linhas $timezones = [];para $timezones = array();e $offsets = [];para $offsets = array();.
Daniel Williams

24

Eu faria isso com o código a seguir, que é semelhante à resposta aceita (sei que o código pode ser refatorado :)):

    $list = DateTimeZone::listAbbreviations();
    $idents = DateTimeZone::listIdentifiers();

    $data = $offset = $added = array();
    foreach ($list as $abbr => $info) {
        foreach ($info as $zone) {
            if ( ! empty($zone['timezone_id'])
                AND
                ! in_array($zone['timezone_id'], $added)
                AND 
                  in_array($zone['timezone_id'], $idents)) {
                $z = new DateTimeZone($zone['timezone_id']);
                $c = new DateTime(null, $z);
                $zone['time'] = $c->format('H:i a');
                $offset[] = $zone['offset'] = $z->getOffset($c);
                $data[] = $zone;
                $added[] = $zone['timezone_id'];
            }
        }
    }

    array_multisort($offset, SORT_ASC, $data);
    $options = array();
    foreach ($data as $key => $row) {
        $options[$row['timezone_id']] = $row['time'] . ' - '
                                        . formatOffset($row['offset']) 
                                        . ' ' . $row['timezone_id'];
    }

    // now you can use $options;

function formatOffset($offset) {
        $hours = $offset / 3600;
        $remainder = $offset % 3600;
        $sign = $hours > 0 ? '+' : '-';
        $hour = (int) abs($hours);
        $minutes = (int) abs($remainder / 60);

        if ($hour == 0 AND $minutes == 0) {
            $sign = ' ';
        }
        return 'GMT' . $sign . str_pad($hour, 2, '0', STR_PAD_LEFT) 
                .':'. str_pad($minutes,2, '0');

}

Produz algo como:

<option value="America/Boise" label="02:10 am - GMT-06:00 America/Boise">02:10 am - GMT-06:00 America/Boise</option>

<option value="America/Denver" label="02:10 am - GMT-06:00 America/Denver">02:10 am - GMT-06:00 America/Denver</option>
<option value="America/Edmonton" label="02:10 am - GMT-06:00 America/Edmonton">02:10 am - GMT-06:00 America/Edmonton</option>
<option value="America/Inuvik" label="02:10 am - GMT-06:00 America/Inuvik">02:10 am - GMT-06:00 America/Inuvik</option>
<option value="America/Shiprock" label="02:10 am - GMT-06:00 America/Shiprock">02:10 am - GMT-06:00 America/Shiprock</option>

<option value="America/Belize" label="02:10 am - GMT-05:00 America/Belize">02:10 am - GMT-05:00 America/Belize</option>

Espero que ajude um pouco e / ou inspire você a vir com algo melhor.


3
Obrigado, quanto mais opções, melhor. Listagem tempo real também ajuda as pessoas que não sabem o fuso horário em que estão.
Xeoncross

Boa ideia! Eu tentei através de copiar / colar e, embora a saída pareça descrita, alguns dos desvios do GMT estavam errados (embora fosse a hora certa). Por exemplo, no inverno (horário padrão), a América / Detroit mostrou um deslocamento GMT de -6, embora esteja no EST (-5). Havia também um grupo listando GMT-4 e até um GMT-2 (America / Pangnirtung), embora todos tivessem o mesmo tempo que New_York corretamente. O problema era que $ row ['offset'] tem o deslocamento original de listAbbreviations () não ajustado para o tempo atual. Adicionar $zone['offset'] = $z->getOffset($c);antes $data[] = $zone;corrige os deslocamentos exibidos.
sootsnoot

2
Esta resposta gera informações de deslocamento incorretas (históricas) ! Por exemplo, "Europa / Amsterdã" mostra "GMT + 00: 20", que não está mais em uso desde 1940. Dê uma olhada na minha resposta na qual explico o problema. Use minha resposta ou outra resposta que não depende DateTimeZone::listAbbreviations, para obter uma lista correta de fusos horários.
Jonathan

21

Você pode criar uma lista suspensa muito fácil a partir dessa matriz (era uma tarefa demorada reunir isso e testá-lo). Já usamos essa lista em alguns de nossos aplicativos.

É muito importante armazenar identificadores de fuso horário no seu banco de dados e não apenas o deslocamento do fuso horário como "GMT + 2", devido ao horário de verão.

ATUALIZAR

Atualizei / corrigi a lista de fusos horários (também faça o checkout: https://github.com/paptamas/timezones ):

<?php
$timezones = array (
'(GMT-11:00) Midway Island' => 'Pacific/Midway',
'(GMT-11:00) Samoa' => 'Pacific/Samoa',
'(GMT-10:00) Hawaii' => 'Pacific/Honolulu',
'(GMT-09:00) Alaska' => 'US/Alaska',
'(GMT-08:00) Pacific Time (US &amp; Canada)' => 'America/Los_Angeles',
'(GMT-08:00) Tijuana' => 'America/Tijuana',
'(GMT-07:00) Arizona' => 'US/Arizona',
'(GMT-07:00) Chihuahua' => 'America/Chihuahua',
'(GMT-07:00) La Paz' => 'America/Chihuahua',
'(GMT-07:00) Mazatlan' => 'America/Mazatlan',
'(GMT-07:00) Mountain Time (US &amp; Canada)' => 'US/Mountain',
'(GMT-06:00) Central America' => 'America/Managua',
'(GMT-06:00) Central Time (US &amp; Canada)' => 'US/Central',
'(GMT-06:00) Guadalajara' => 'America/Mexico_City',
'(GMT-06:00) Mexico City' => 'America/Mexico_City',
'(GMT-06:00) Monterrey' => 'America/Monterrey',
'(GMT-06:00) Saskatchewan' => 'Canada/Saskatchewan',
'(GMT-05:00) Bogota' => 'America/Bogota',
'(GMT-05:00) Eastern Time (US &amp; Canada)' => 'US/Eastern',
'(GMT-05:00) Indiana (East)' => 'US/East-Indiana',
'(GMT-05:00) Lima' => 'America/Lima',
'(GMT-05:00) Quito' => 'America/Bogota',
'(GMT-04:00) Atlantic Time (Canada)' => 'Canada/Atlantic',
'(GMT-04:30) Caracas' => 'America/Caracas',
'(GMT-04:00) La Paz' => 'America/La_Paz',
'(GMT-04:00) Santiago' => 'America/Santiago',
'(GMT-03:30) Newfoundland' => 'Canada/Newfoundland',
'(GMT-03:00) Brasilia' => 'America/Sao_Paulo',
'(GMT-03:00) Buenos Aires' => 'America/Argentina/Buenos_Aires',
'(GMT-03:00) Georgetown' => 'America/Argentina/Buenos_Aires',
'(GMT-03:00) Greenland' => 'America/Godthab',
'(GMT-02:00) Mid-Atlantic' => 'America/Noronha',
'(GMT-01:00) Azores' => 'Atlantic/Azores',
'(GMT-01:00) Cape Verde Is.' => 'Atlantic/Cape_Verde',
'(GMT+00:00) Casablanca' => 'Africa/Casablanca',
'(GMT+00:00) Edinburgh' => 'Europe/London',
'(GMT+00:00) Greenwich Mean Time : Dublin' => 'Etc/Greenwich',
'(GMT+00:00) Lisbon' => 'Europe/Lisbon',
'(GMT+00:00) London' => 'Europe/London',
'(GMT+00:00) Monrovia' => 'Africa/Monrovia',
'(GMT+00:00) UTC' => 'UTC',
'(GMT+01:00) Amsterdam' => 'Europe/Amsterdam',
'(GMT+01:00) Belgrade' => 'Europe/Belgrade',
'(GMT+01:00) Berlin' => 'Europe/Berlin',
'(GMT+01:00) Bern' => 'Europe/Berlin',
'(GMT+01:00) Bratislava' => 'Europe/Bratislava',
'(GMT+01:00) Brussels' => 'Europe/Brussels',
'(GMT+01:00) Budapest' => 'Europe/Budapest',
'(GMT+01:00) Copenhagen' => 'Europe/Copenhagen',
'(GMT+01:00) Ljubljana' => 'Europe/Ljubljana',
'(GMT+01:00) Madrid' => 'Europe/Madrid',
'(GMT+01:00) Paris' => 'Europe/Paris',
'(GMT+01:00) Prague' => 'Europe/Prague',
'(GMT+01:00) Rome' => 'Europe/Rome',
'(GMT+01:00) Sarajevo' => 'Europe/Sarajevo',
'(GMT+01:00) Skopje' => 'Europe/Skopje',
'(GMT+01:00) Stockholm' => 'Europe/Stockholm',
'(GMT+01:00) Vienna' => 'Europe/Vienna',
'(GMT+01:00) Warsaw' => 'Europe/Warsaw',
'(GMT+01:00) West Central Africa' => 'Africa/Lagos',
'(GMT+01:00) Zagreb' => 'Europe/Zagreb',
'(GMT+02:00) Athens' => 'Europe/Athens',
'(GMT+02:00) Bucharest' => 'Europe/Bucharest',
'(GMT+02:00) Cairo' => 'Africa/Cairo',
'(GMT+02:00) Harare' => 'Africa/Harare',
'(GMT+02:00) Helsinki' => 'Europe/Helsinki',
'(GMT+02:00) Istanbul' => 'Europe/Istanbul',
'(GMT+02:00) Jerusalem' => 'Asia/Jerusalem',
'(GMT+02:00) Kyiv' => 'Europe/Helsinki',
'(GMT+02:00) Pretoria' => 'Africa/Johannesburg',
'(GMT+02:00) Riga' => 'Europe/Riga',
'(GMT+02:00) Sofia' => 'Europe/Sofia',
'(GMT+02:00) Tallinn' => 'Europe/Tallinn',
'(GMT+02:00) Vilnius' => 'Europe/Vilnius',
'(GMT+03:00) Baghdad' => 'Asia/Baghdad',
'(GMT+03:00) Kuwait' => 'Asia/Kuwait',
'(GMT+03:00) Minsk' => 'Europe/Minsk',
'(GMT+03:00) Nairobi' => 'Africa/Nairobi',
'(GMT+03:00) Riyadh' => 'Asia/Riyadh',
'(GMT+03:00) Volgograd' => 'Europe/Volgograd',
'(GMT+03:30) Tehran' => 'Asia/Tehran',
'(GMT+04:00) Abu Dhabi' => 'Asia/Muscat',
'(GMT+04:00) Baku' => 'Asia/Baku',
'(GMT+04:00) Moscow' => 'Europe/Moscow',
'(GMT+04:00) Muscat' => 'Asia/Muscat',
'(GMT+04:00) St. Petersburg' => 'Europe/Moscow',
'(GMT+04:00) Tbilisi' => 'Asia/Tbilisi',
'(GMT+04:00) Yerevan' => 'Asia/Yerevan',
'(GMT+04:30) Kabul' => 'Asia/Kabul',
'(GMT+05:00) Islamabad' => 'Asia/Karachi',
'(GMT+05:00) Karachi' => 'Asia/Karachi',
'(GMT+05:00) Tashkent' => 'Asia/Tashkent',
'(GMT+05:30) Chennai' => 'Asia/Calcutta',
'(GMT+05:30) Kolkata' => 'Asia/Kolkata',
'(GMT+05:30) Mumbai' => 'Asia/Calcutta',
'(GMT+05:30) New Delhi' => 'Asia/Calcutta',
'(GMT+05:30) Sri Jayawardenepura' => 'Asia/Calcutta',
'(GMT+05:45) Kathmandu' => 'Asia/Katmandu',
'(GMT+06:00) Almaty' => 'Asia/Almaty',
'(GMT+06:00) Astana' => 'Asia/Dhaka',
'(GMT+06:00) Dhaka' => 'Asia/Dhaka',
'(GMT+06:00) Ekaterinburg' => 'Asia/Yekaterinburg',
'(GMT+06:30) Rangoon' => 'Asia/Rangoon',
'(GMT+07:00) Bangkok' => 'Asia/Bangkok',
'(GMT+07:00) Hanoi' => 'Asia/Bangkok',
'(GMT+07:00) Jakarta' => 'Asia/Jakarta',
'(GMT+07:00) Novosibirsk' => 'Asia/Novosibirsk',
'(GMT+08:00) Beijing' => 'Asia/Hong_Kong',
'(GMT+08:00) Chongqing' => 'Asia/Chongqing',
'(GMT+08:00) Hong Kong' => 'Asia/Hong_Kong',
'(GMT+08:00) Krasnoyarsk' => 'Asia/Krasnoyarsk',
'(GMT+08:00) Kuala Lumpur' => 'Asia/Kuala_Lumpur',
'(GMT+08:00) Perth' => 'Australia/Perth',
'(GMT+08:00) Singapore' => 'Asia/Singapore',
'(GMT+08:00) Taipei' => 'Asia/Taipei',
'(GMT+08:00) Ulaan Bataar' => 'Asia/Ulan_Bator',
'(GMT+08:00) Urumqi' => 'Asia/Urumqi',
'(GMT+09:00) Irkutsk' => 'Asia/Irkutsk',
'(GMT+09:00) Osaka' => 'Asia/Tokyo',
'(GMT+09:00) Sapporo' => 'Asia/Tokyo',
'(GMT+09:00) Seoul' => 'Asia/Seoul',
'(GMT+09:00) Tokyo' => 'Asia/Tokyo',
'(GMT+09:30) Adelaide' => 'Australia/Adelaide',
'(GMT+09:30) Darwin' => 'Australia/Darwin',
'(GMT+10:00) Brisbane' => 'Australia/Brisbane',
'(GMT+10:00) Canberra' => 'Australia/Canberra',
'(GMT+10:00) Guam' => 'Pacific/Guam',
'(GMT+10:00) Hobart' => 'Australia/Hobart',
'(GMT+10:00) Melbourne' => 'Australia/Melbourne',
'(GMT+10:00) Port Moresby' => 'Pacific/Port_Moresby',
'(GMT+10:00) Sydney' => 'Australia/Sydney',
'(GMT+10:00) Yakutsk' => 'Asia/Yakutsk',
'(GMT+11:00) Vladivostok' => 'Asia/Vladivostok',
'(GMT+12:00) Auckland' => 'Pacific/Auckland',
'(GMT+12:00) Fiji' => 'Pacific/Fiji',
'(GMT+12:00) International Date Line West' => 'Pacific/Kwajalein',
'(GMT+12:00) Kamchatka' => 'Asia/Kamchatka',
'(GMT+12:00) Magadan' => 'Asia/Magadan',
'(GMT+12:00) Marshall Is.' => 'Pacific/Fiji',
'(GMT+12:00) New Caledonia' => 'Asia/Magadan',
'(GMT+12:00) Solomon Is.' => 'Asia/Magadan',
'(GMT+12:00) Wellington' => 'Pacific/Auckland',
'(GMT+13:00) Nuku\'alofa' => 'Pacific/Tongatapu'
);
?>   

9
Os fusos horários podem mudar, então eu recomendo usar a lista de fusos horários do PHP a cada momento (e não usar uma matriz codificada, como você sugere).
Jonathan

4

Editando a resposta do Tamas para remover todas as "outras" entradas que o site php.net diz que não devem mais ser usadas.

Talvez não importe, mas apenas seguindo as práticas recomendadas. Consulte o aviso na parte inferior de: http://fr2.php.net/manual/en/timezones.others.php

Além disso, embora esta lista tenha os Açores como GMT -1, na verdade acho que é o mesmo (pelo menos às vezes) como GMT, mas não tenho certeza.

Edição para oferecer isso no sql, para que você possa criar a lista suspensa em um formulário e, em vez disso, vincular a resposta do usuário a um índice.

Editando novamente para remover o espaço inicial

CREATE TABLE IF NOT EXISTS `timezones` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(44) DEFAULT NULL,
  `timezone` varchar(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=141 ;

--
-- Dumping data for table `timezones`
--

INSERT INTO `timezones` (`id`, `name`, `timezone`) VALUES
(1, '(GMT-11:00) Midway Island ', 'Pacific/Midway'),
(2, '(GMT-11:00) Samoa ', 'Pacific/Samoa'),
(3, '(GMT-10:00) Hawaii ', 'Pacific/Honolulu'),
(4, '(GMT-09:00) Alaska ', 'America/Anchorage'),
(5, '(GMT-08:00) Pacific Time (US &amp; Canada) ', 'America/Los_Angeles'),
(6, '(GMT-08:00) Tijuana ', 'America/Tijuana'),
(7, '(GMT-07:00) Chihuahua ', 'America/Chihuahua'),
(8, '(GMT-07:00) La Paz ', 'America/Chihuahua'),
(9, '(GMT-07:00) Mazatlan ', 'America/Mazatlan'),
(10, '(GMT-07:00) Mountain Time (US &amp; Canada) ', 'America/Denver'),
(11, '(GMT-06:00) Central America ', 'America/Managua'),
(12, '(GMT-06:00) Central Time (US &amp; Canada) ', 'America/Chicago'),
(13, '(GMT-06:00) Guadalajara ', 'America/Mexico_City'),
(14, '(GMT-06:00) Mexico City ', 'America/Mexico_City'),
(15, '(GMT-06:00) Monterrey ', 'America/Monterrey'),
(16, '(GMT-05:00) Bogota ', 'America/Bogota'),
(17, '(GMT-05:00) Eastern Time (US &amp; Canada) ', 'America/New_York'),
(18, '(GMT-05:00) Lima ', 'America/Lima'),
(19, '(GMT-05:00) Quito ', 'America/Bogota'),
(20, '(GMT-04:00) Atlantic Time (Canada) ', 'Canada/Atlantic'),
(21, '(GMT-04:30) Caracas ', 'America/Caracas'),
(22, '(GMT-04:00) La Paz ', 'America/La_Paz'),
(23, '(GMT-04:00) Santiago ', 'America/Santiago'),
(24, '(GMT-03:30) Newfoundland ', 'America/St_Johns'),
(25, '(GMT-03:00) Brasilia ', 'America/Sao_Paulo'),
(26, '(GMT-03:00) Buenos Aires ', 'America/Argentina/Buenos_Aires'),
(27, '(GMT-03:00) Georgetown ', 'America/Argentina/Buenos_Aires'),
(28, '(GMT-03:00) Greenland ', 'America/Godthab'),
(29, '(GMT-02:00) Mid-Atlantic ', 'America/Noronha'),
(30, '(GMT-01:00) Azores ', 'Atlantic/Azores'),
(31, '(GMT-01:00) Cape Verde Is. ', 'Atlantic/Cape_Verde'),
(32, '(GMT+00:00) Casablanca ', 'Africa/Casablanca'),
(33, '(GMT+00:00) Edinburgh ', 'Europe/London'),
(34, '(GMT+00:00) Dublin ', 'Europe/Dublin'),
(35, '(GMT+00:00) Lisbon ', 'Europe/Lisbon'),
(36, '(GMT+00:00) London ', 'Europe/London'),
(37, '(GMT+00:00) Monrovia ', 'Africa/Monrovia'),
(38, '(GMT+00:00) UTC ', 'UTC'),
(39, '(GMT+01:00) Amsterdam ', 'Europe/Amsterdam'),
(40, '(GMT+01:00) Belgrade ', 'Europe/Belgrade'),
(41, '(GMT+01:00) Berlin ', 'Europe/Berlin'),
(42, '(GMT+01:00) Bern ', 'Europe/Berlin'),
(43, '(GMT+01:00) Bratislava ', 'Europe/Bratislava'),
(44, '(GMT+01:00) Brussels ', 'Europe/Brussels'),
(45, '(GMT+01:00) Budapest ', 'Europe/Budapest'),
(46, '(GMT+01:00) Copenhagen ', 'Europe/Copenhagen'),
(47, '(GMT+01:00) Ljubljana ', 'Europe/Ljubljana'),
(48, '(GMT+01:00) Madrid ', 'Europe/Madrid'),
(49, '(GMT+01:00) Paris ', 'Europe/Paris'),
(50, '(GMT+01:00) Prague ', 'Europe/Prague'),
(51, '(GMT+01:00) Rome ', 'Europe/Rome'),
(52, '(GMT+01:00) Sarajevo ', 'Europe/Sarajevo'),
(53, '(GMT+01:00) Skopje ', 'Europe/Skopje'),
(54, '(GMT+01:00) Stockholm ', 'Europe/Stockholm'),
(55, '(GMT+01:00) Vienna ', 'Europe/Vienna'),
(56, '(GMT+01:00) Warsaw ', 'Europe/Warsaw'),
(57, '(GMT+01:00) West Central Africa ', 'Africa/Lagos'),
(58, '(GMT+01:00) Zagreb ', 'Europe/Zagreb'),
(59, '(GMT+02:00) Athens ', 'Europe/Athens'),
(60, '(GMT+02:00) Bucharest ', 'Europe/Bucharest'),
(61, '(GMT+02:00) Cairo ', 'Africa/Cairo'),
(62, '(GMT+02:00) Harare ', 'Africa/Harare'),
(63, '(GMT+02:00) Helsinki ', 'Europe/Helsinki'),
(64, '(GMT+02:00) Istanbul ', 'Europe/Istanbul'),
(65, '(GMT+02:00) Jerusalem ', 'Asia/Jerusalem'),
(66, '(GMT+02:00) Kyiv ', 'Europe/Helsinki'),
(67, '(GMT+02:00) Pretoria ', 'Africa/Johannesburg'),
(68, '(GMT+02:00) Riga ', 'Europe/Riga'),
(69, '(GMT+02:00) Sofia ', 'Europe/Sofia'),
(70, '(GMT+02:00) Tallinn ', 'Europe/Tallinn'),
(71, '(GMT+02:00) Vilnius ', 'Europe/Vilnius'),
(72, '(GMT+03:00) Baghdad ', 'Asia/Baghdad'),
(73, '(GMT+03:00) Kuwait ', 'Asia/Kuwait'),
(74, '(GMT+03:00) Minsk ', 'Europe/Minsk'),
(75, '(GMT+03:00) Nairobi ', 'Africa/Nairobi'),
(76, '(GMT+03:00) Riyadh ', 'Asia/Riyadh'),
(77, '(GMT+03:00) Volgograd ', 'Europe/Volgograd'),
(78, '(GMT+03:30) Tehran ', 'Asia/Tehran'),
(79, '(GMT+04:00) Abu Dhabi ', 'Asia/Muscat'),
(80, '(GMT+04:00) Baku ', 'Asia/Baku'),
(81, '(GMT+04:00) Moscow ', 'Europe/Moscow'),
(82, '(GMT+04:00) Muscat ', 'Asia/Muscat'),
(83, '(GMT+04:00) St. Petersburg ', 'Europe/Moscow'),
(84, '(GMT+04:00) Tbilisi ', 'Asia/Tbilisi'),
(85, '(GMT+04:00) Yerevan ', 'Asia/Yerevan'),
(86, '(GMT+04:30) Kabul ', 'Asia/Kabul'),
(87, '(GMT+05:00) Islamabad ', 'Asia/Karachi'),
(88, '(GMT+05:00) Karachi ', 'Asia/Karachi'),
(89, '(GMT+05:00) Tashkent ', 'Asia/Tashkent'),
(90, '(GMT+05:30) Chennai ', 'Asia/Calcutta'),
(91, '(GMT+05:30) Kolkata ', 'Asia/Kolkata'),
(92, '(GMT+05:30) Mumbai ', 'Asia/Calcutta'),
(93, '(GMT+05:30) New Delhi ', 'Asia/Calcutta'),
(94, '(GMT+05:30) Sri Jayawardenepura ', 'Asia/Calcutta'),
(95, '(GMT+05:45) Kathmandu ', 'Asia/Katmandu'),
(96, '(GMT+06:00) Almaty ', 'Asia/Almaty'),
(97, '(GMT+06:00) Astana ', 'Asia/Dhaka'),
(98, '(GMT+06:00) Dhaka ', 'Asia/Dhaka'),
(99, '(GMT+06:00) Ekaterinburg ', 'Asia/Yekaterinburg'),
(100, '(GMT+06:30) Rangoon ', 'Asia/Rangoon'),
(101, '(GMT+07:00) Bangkok ', 'Asia/Bangkok'),
(102, '(GMT+07:00) Hanoi ', 'Asia/Bangkok'),
(103, '(GMT+07:00) Jakarta ', 'Asia/Jakarta'),
(104, '(GMT+07:00) Novosibirsk ', 'Asia/Novosibirsk'),
(105, '(GMT+08:00) Beijing ', 'Asia/Hong_Kong'),
(106, '(GMT+08:00) Chongqing ', 'Asia/Chongqing'),
(107, '(GMT+08:00) Hong Kong ', 'Asia/Hong_Kong'),
(108, '(GMT+08:00) Krasnoyarsk ', 'Asia/Krasnoyarsk'),
(109, '(GMT+08:00) Kuala Lumpur ', 'Asia/Kuala_Lumpur'),
(110, '(GMT+08:00) Perth ', 'Australia/Perth'),
(111, '(GMT+08:00) Singapore ', 'Asia/Singapore'),
(112, '(GMT+08:00) Taipei ', 'Asia/Taipei'),
(113, '(GMT+08:00) Ulaan Bataar ', 'Asia/Ulan_Bator'),
(114, '(GMT+08:00) Urumqi ', 'Asia/Urumqi'),
(115, '(GMT+09:00) Irkutsk ', 'Asia/Irkutsk'),
(116, '(GMT+09:00) Osaka ', 'Asia/Tokyo'),
(117, '(GMT+09:00) Sapporo ', 'Asia/Tokyo'),
(118, '(GMT+09:00) Seoul ', 'Asia/Seoul'),
(119, '(GMT+09:00) Tokyo ', 'Asia/Tokyo'),
(120, '(GMT+09:30) Adelaide ', 'Australia/Adelaide'),
(121, '(GMT+09:30) Darwin ', 'Australia/Darwin'),
(122, '(GMT+10:00) Brisbane ', 'Australia/Brisbane'),
(123, '(GMT+10:00) Canberra ', 'Australia/Canberra'),
(124, '(GMT+10:00) Guam ', 'Pacific/Guam'),
(125, '(GMT+10:00) Hobart ', 'Australia/Hobart'),
(126, '(GMT+10:00) Melbourne ', 'Australia/Melbourne'),
(127, '(GMT+10:00) Port Moresby ', 'Pacific/Port_Moresby'),
(128, '(GMT+10:00) Sydney ', 'Australia/Sydney'),
(129, '(GMT+10:00) Yakutsk ', 'Asia/Yakutsk'),
(130, '(GMT+11:00) Vladivostok ', 'Asia/Vladivostok'),
(131, '(GMT+12:00) Auckland ', 'Pacific/Auckland'),
(132, '(GMT+12:00) Fiji ', 'Pacific/Fiji'),
(133, '(GMT+12:00) International Date Line West ', 'Pacific/Kwajalein'),
(134, '(GMT+12:00) Kamchatka ', 'Asia/Kamchatka'),
(135, '(GMT+12:00) Magadan ', 'Asia/Magadan'),
(136, '(GMT+12:00) Marshall Is. ', 'Pacific/Fiji'),
(137, '(GMT+12:00) New Caledonia ', 'Asia/Magadan'),
(138, '(GMT+12:00) Solomon Is. ', 'Asia/Magadan'),
(139, '(GMT+12:00) Wellington ', 'Pacific/Auckland'),
(140, '(GMT+13:00) Nuku\\alofa ', 'Pacific/Tongatapu');

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

3

Aqui está um que cria uma matriz multidimensional classificada por deslocamento e nome legal:

function timezones() {
    $timezones = [];

    foreach (timezone_identifiers_list() as $timezone) {
        $datetime = new \DateTime('now', new DateTimeZone($timezone));
        $timezones[] = [
            'sort' => str_replace(':', '', $datetime->format('P')),
            'offset' => $datetime->format('P'),
            'name' => str_replace('_', ' ', implode(', ', explode('/', $timezone))),
            'timezone' => $timezone,
        ];
    }

    usort($timezones, function($a, $b) {
        return $a['sort'] - $b['sort'] ?: strcmp($a['name'], $b['name']);
    });

    return $timezones;
}

foreach (timezones() as $timezone) {
    echo '(UTC '.$timezone['offset'].') '.$timezone['name'].'<br>';
}

Echos:

(UTC -11:00) Pacific, Midway
(UTC -11:00) Pacific, Niue
(UTC -11:00) Pacific, Pago Pago
(UTC -10:00) Pacific, Honolulu
(UTC -10:00) Pacific, Johnston
(UTC -10:00) Pacific, Rarotonga
(UTC -10:00) Pacific, Tahiti
(UTC -09:30) Pacific, Marquesas
(UTC -09:00) America, Adak
(UTC -09:00) Pacific, Gambier
(UTC -08:00) America, Anchorage
(UTC -08:00) America, Juneau
...

3
$timezone = array(
    'Pacific/Midway' => '(GMT-11:00) Midway Island, Samoa',
    'America/Adak' => '(GMT-10:00) Hawaii-Aleutian',
    'Etc/GMT+10' => '(GMT-10:00) Hawaii',
    'Pacific/Marquesas' => '(GMT-09:30) Marquesas Islands',
    'Pacific/Gambier' => '(GMT-09:00) Gambier Islands',
    'America/Anchorage' => '(GMT-09:00) Alaska',
    'America/Ensenada' => '(GMT-08:00) Tijuana, Baja California',
    'Etc/GMT+8' => '(GMT-08:00) Pitcairn Islands',
    'America/Los_Angeles' => '(GMT-08:00) Pacific Time (US & Canada)',
    'America/Denver' => '(GMT-07:00) Mountain Time (US & Canada)',
    'America/Chihuahua' => '(GMT-07:00) Chihuahua, La Paz, Mazatlan',
    'America/Dawson_Creek' => '(GMT-07:00) Arizona',
    'America/Belize' => '(GMT-06:00) Saskatchewan, Central America',
    'America/Cancun' => '(GMT-06:00) Guadalajara, Mexico City, Monterrey',
    'Chile/EasterIsland' => '(GMT-06:00) Easter Island',
    'America/Chicago' => '(GMT-06:00) Central Time (US & Canada)',
    'America/New_York' => '(GMT-05:00) Eastern Time (US & Canada)',
    'America/Havana' => '(GMT-05:00) Cuba',
    'America/Bogota' => '(GMT-05:00) Bogota, Lima, Quito, Rio Branco',
    'America/Caracas' => '(GMT-04:30) Caracas',
    'America/Santiago' => '(GMT-04:00) Santiago',
    'America/La_Paz' => '(GMT-04:00) La Paz',
    'Atlantic/Stanley' => '(GMT-04:00) Faukland Islands',
    'America/Campo_Grande' => '(GMT-04:00) Brazil',
    'America/Goose_Bay' => '(GMT-04:00) Atlantic Time (Goose Bay)',
    'America/Glace_Bay' => '(GMT-04:00) Atlantic Time (Canada)',
    'America/St_Johns' => '(GMT-03:30) Newfoundland',
    'America/Araguaina' => '(GMT-03:00) UTC-3',
    'America/Montevideo' => '(GMT-03:00) Montevideo',
    'America/Miquelon' => '(GMT-03:00) Miquelon, St. Pierre',
    'America/Godthab' => '(GMT-03:00) Greenland',
    'America/Argentina/Buenos_Aires' => '(GMT-03:00) Buenos Aires',
    'America/Sao_Paulo' => '(GMT-03:00) Brasilia',
    'America/Noronha' => '(GMT-02:00) Mid-Atlantic',
    'Atlantic/Cape_Verde' => '(GMT-01:00) Cape Verde Is.',
    'Atlantic/Azores' => '(GMT-01:00) Azores',
    'Europe/Belfast' => '(GMT) Greenwich Mean Time : Belfast',
    'Europe/Dublin' => '(GMT) Greenwich Mean Time : Dublin',
    'Europe/Lisbon' => '(GMT) Greenwich Mean Time : Lisbon',
    'Europe/London' => '(GMT) Greenwich Mean Time : London',
    'Africa/Abidjan' => '(GMT) Monrovia, Reykjavik',
    'Europe/Amsterdam' => '(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna',
    'Europe/Belgrade' => '(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague',
    'Europe/Brussels' => '(GMT+01:00) Brussels, Copenhagen, Madrid, Paris',
    'Africa/Algiers' => '(GMT+01:00) West Central Africa',
    'Africa/Windhoek' => '(GMT+01:00) Windhoek',
    'Asia/Beirut' => '(GMT+02:00) Beirut',
    'Africa/Cairo' => '(GMT+02:00) Cairo',
    'Asia/Gaza' => '(GMT+02:00) Gaza',
    'Africa/Blantyre' => '(GMT+02:00) Harare, Pretoria',
    'Asia/Jerusalem' => '(GMT+02:00) Jerusalem',
    'Europe/Minsk' => '(GMT+02:00) Minsk',
    'Asia/Damascus' => '(GMT+02:00) Syria',
    'Europe/Moscow' => '(GMT+03:00) Moscow, St. Petersburg, Volgograd',
    'Africa/Addis_Ababa' => '(GMT+03:00) Nairobi',
    'Asia/Tehran' => '(GMT+03:30) Tehran',
    'Asia/Dubai' => '(GMT+04:00) Abu Dhabi, Muscat',
    'Asia/Yerevan' => '(GMT+04:00) Yerevan',
    'Asia/Kabul' => '(GMT+04:30) Kabul',
    'Asia/Yekaterinburg' => '(GMT+05:00) Ekaterinburg',
    'Asia/Tashkent' => '(GMT+05:00) Tashkent',
    'Asia/Kolkata' => '(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi',
    'Asia/Katmandu' => '(GMT+05:45) Kathmandu',
    'Asia/Dhaka' => '(GMT+06:00) Astana, Dhaka',
    'Asia/Novosibirsk' => '(GMT+06:00) Novosibirsk',
    'Asia/Rangoon' => '(GMT+06:30) Yangon (Rangoon)',
    'Asia/Bangkok' => '(GMT+07:00) Bangkok, Hanoi, Jakarta',
    'Asia/Krasnoyarsk' => '(GMT+07:00) Krasnoyarsk',
    'Asia/Hong_Kong' => '(GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi',
    'Asia/Irkutsk' => '(GMT+08:00) Irkutsk, Ulaan Bataar',
    'Australia/Perth' => '(GMT+08:00) Perth',
    'Australia/Eucla' => '(GMT+08:45) Eucla',
    'Asia/Tokyo' => '(GMT+09:00) Osaka, Sapporo, Tokyo',
    'Asia/Seoul' => '(GMT+09:00) Seoul',
    'Asia/Yakutsk' => '(GMT+09:00) Yakutsk',
    'Australia/Adelaide' => '(GMT+09:30) Adelaide',
    'Australia/Darwin' => '(GMT+09:30) Darwin',
    'Australia/Brisbane' => '(GMT+10:00) Brisbane',
    'Australia/Hobart' => '(GMT+10:00) Hobart',
    'Asia/Vladivostok' => '(GMT+10:00) Vladivostok',
    'Australia/Lord_Howe' => '(GMT+10:30) Lord Howe Island',
    'Etc/GMT-11' => '(GMT+11:00) Solomon Is., New Caledonia',
    'Asia/Magadan' => '(GMT+11:00) Magadan',
    'Pacific/Norfolk' => '(GMT+11:30) Norfolk Island',
    'Asia/Anadyr' => '(GMT+12:00) Anadyr, Kamchatka',
    'Pacific/Auckland' => '(GMT+12:00) Auckland, Wellington',
    'Etc/GMT-12' => '(GMT+12:00) Fiji, Kamchatka, Marshall Is.',
    'Pacific/Chatham' => '(GMT+12:45) Chatham Islands',
    'Pacific/Tongatapu' => '(GMT+13:00) Nukualofa',
    'Pacific/Kiritimati' => '(GMT+14:00) Kiritimati',

date_default_timezone_set($timezone);

@PranavKaistha At Kinko's.
FredTheWebGuy

2

O uso de listAbbreviations () não faz sentido, pois em todas as áreas ele retorna todos os diferentes deslocamentos que foram historicamente usados ​​ali, não apenas os atuais. A fonte base correta da lista é definitivamente listIdentifiers ().

Eu geraria a lista apenas uma vez e a salvaria para evitar gerá-la para cada solicitação. Eu poderia atualizá-lo uma vez por mês.

Além disso, eu poderia colocar todas as informações de fuso horário em um script js separado e gerar a própria lista de seleção no lado do cliente. O script js também pode ser armazenado em cache, os fusos horários não mudam frequentemente.

Além disso, usando javascript no lado do cliente, você pode saber a hora local atual e, portanto, pode encontrar as zonas que possuem a mesma hora agora (os minutos podem ser diferentes, portanto a comparação deve ser aproximada) e exibi-los na parte superior do lista, para que o usuário não precise rolar por todos os 400 itens. Você também pode exibir as zonas adjacentes (+/- 1 hora) a seguir.


2

Sei que isso já tem uma resposta, mas vi uma oportunidade de melhorar uma das respostas aqui. Toland H postou um código muito bom que faz exatamente o que a pergunta estava pedindo. Abaixo está uma versão abreviada e expandida do código de Toland H:

  • A função coloca tudo em tags de opção para você. Apenas faça eco do retorno entre as tags selecionadas.
  • Melhorias importantes: a lista é classificada primeiro por continente e organizada em grupos de opções com base em continentes. Torna muito amigável para os visitantes que escolhem seu fuso horário.

function generate_timezone_list() {
static $allRegions = array(
DateTimeZone::AFRICA,
DateTimeZone::AMERICA,
DateTimeZone::ANTARCTICA,
DateTimeZone::ASIA,
DateTimeZone::ATLANTIC,
DateTimeZone::AUSTRALIA,
DateTimeZone::EUROPE,
DateTimeZone::INDIAN,
DateTimeZone::PACIFIC
);
// Makes it easier to create option groups next
$list = array ('AFRICA','AMERICA','ANTARCTICA','ASIA','ATLANTIC','AUSTRALIA','EUROPE','INDIAN','PACIFIC');
// Make array holding the regions (continents), they are arrays w/ all their cities
$region = array();
foreach ($allRegions as $area){
array_push ($region,DateTimeZone::listIdentifiers( $area ));
}   
$count = count ($region); $i = 0; $holder = '';
// Go through each region one by one, sorting and formatting it's cities
while ($i < $count){
$chunck = $region[$i];
// Create the region (continents) option group
$holder .= '<optgroup label="---------- '.$list[$i].' ----------">';
$timezone_offsets = array();
foreach( $chunck as $timezone ){
$tz = new DateTimeZone($timezone);
$timezone_offsets[$timezone] = $tz->getOffset(new DateTime);
}
asort ($timezone_offsets);
$timezone_list = array();
foreach ($timezone_offsets as $timezone => $offset){
$offset_prefix = $offset < 0 ? '-' : '+';
$offset_formatted = gmdate( 'H:i', abs($offset) );
$pretty_offset = "UTC ${offset_prefix}${offset_formatted}";
$timezone_list[$timezone] = "(${pretty_offset}) $timezone";     
}
// All the formatting is done, finish and move on to next region
foreach ($timezone_list as $key => $val){
$holder .= '<option value="'.$key.'">'.$val.'</option>';
}
$holder .= '</optgroup>';
++$i;
}
return $holder;
}
echo "<select>".generate_timezone_list()."</select>";

Então tudo que você precisa fazer é repetir o que é retornado entre as tags de seleção html. Você receberá uma lista de seleção mais ou menos assim:

----- AFRICA -----
(UTC +00:00) Africa/ city name
(UTC +01:00) Africa/ city name
(UTC +02:00) Africa/ city name
(UTC +02:00) Africa/ city name
----- AMERICA -----
(UTC -09:00) America/ city name
(UTC -07:00) America/ city name
(UTC +02:00) America/ city name
(UTC +05:00) America/ city name

E assim por diante...


2

Esta função PHP faz o trabalho para você e devolve uma matriz:

function time_zonelist(){
    $return = array();
    $timezone_identifiers_list = timezone_identifiers_list();
    foreach($timezone_identifiers_list as $timezone_identifier){
        $date_time_zone = new DateTimeZone($timezone_identifier);
        $date_time = new DateTime('now', $date_time_zone);
        $hours = floor($date_time_zone->getOffset($date_time) / 3600);
        $mins = floor(($date_time_zone->getOffset($date_time) - ($hours*3600)) / 60);
        $hours = 'GMT' . ($hours < 0 ? $hours : '+'.$hours);
        $mins = ($mins > 0 ? $mins : '0'.$mins);
        $text = str_replace("_"," ",$timezone_identifier);
        $return[$timezone_identifier] = $text.' ('.$hours.':'.$mins.')';
    }
    return $return;
}

Esta função PHP retorna uma matriz de todos os fusos horários existentes, incluindo Offset:

Use-o, por exemplo:

print_r(time_zonelist());

Você poderia explicar o que faz?
Wai Ha Lee

1

Eu queria ter algo mais simples para meus usuários, da maneira que o Google faz ..

$timezones = [
    "AF" => [
        "name" => "Afghanistan" 
    ],
    "AL" => [
        "name" => "Albania" 
    ],
    "DZ" => [
        "name" => "Algeria" 
    ],
    "AS" => [
        "name" => "American Samoa" 
    ],
    "AD" => [
        "name" => "Andorra" 
    ],
    "AQ" => [
        "name" => "Antarctica" 
    ],
    "AG" => [
        "name" => "Antigua & Barbuda" 
    ],
    "AR" => [
        "name" => "Argentina" 
    ],
    "AM" => [
        "name" => "Armenia" 
    ],
    "AU" => [
        "name" => "Australia" 
    ],
    "AT" => [
        "name" => "Austria" 
    ],
    "AZ" => [
        "name" => "Azerbaijan" 
    ],
    "BS" => [
        "name" => "Bahamas" 
    ],
    "BD" => [
        "name" => "Bangladesh" 
    ],
    "BB" => [
        "name" => "Barbados" 
    ],
    "BY" => [
        "name" => "Belarus" 
    ],
    "BE" => [
        "name" => "Belgium" 
    ],
    "BZ" => [
        "name" => "Belize" 
    ],
    "BM" => [
        "name" => "Bermuda" 
    ],
    "BT" => [
        "name" => "Bhutan" 
    ],
    "BO" => [
        "name" => "Bolivia" 
    ],
    "BA" => [
        "name" => "Bosnia & Herzegovina" 
    ],
    "BR" => [
        "name" => "Brazil" 
    ],
    "IO" => [
        "name" => "British Indian Ocean Territory" 
    ],
    "BN" => [
        "name" => "Brunei" 
    ],
    "BG" => [
        "name" => "Bulgaria" 
    ],
    "CA" => [
        "name" => "Canada" 
    ],
    "CV" => [
        "name" => "Cape Verde" 
    ],
    "KY" => [
        "name" => "Cayman Islands" 
    ],
    "TD" => [
        "name" => "Chad" 
    ],
    "CL" => [
        "name" => "Chile" 
    ],
    "CN" => [
        "name" => "China" 
    ],
    "CX" => [
        "name" => "Christmas Island" 
    ],
    "CC" => [
        "name" => "Cocos (Keeling) Islands" 
    ],
    "CO" => [
        "name" => "Colombia" 
    ],
    "CK" => [
        "name" => "Cook Islands" 
    ],
    "CR" => [
        "name" => "Costa Rica" 
    ],
    "CI" => [
        "name" => "Côte d’Ivoire" 
    ],
    "HR" => [
        "name" => "Croatia" 
    ],
    "CU" => [
        "name" => "Cuba" 
    ],
    "CW" => [
        "name" => "Curaçao" 
    ],
    "CY" => [
        "name" => "Cyprus" 
    ],
    "CZ" => [
        "name" => "Czech Republic" 
    ],
    "DK" => [
        "name" => "Denmark" 
    ],
    "DO" => [
        "name" => "Dominican Republic" 
    ],
    "EC" => [
        "name" => "Ecuador" 
    ],
    "EG" => [
        "name" => "Egypt" 
    ],
    "SV" => [
        "name" => "El Salvador" 
    ],
    "EE" => [
        "name" => "Estonia" 
    ],
    "FK" => [
        "name" => "Falkland Islands (Islas Malvinas)" 
    ],
    "FO" => [
        "name" => "Faroe Islands" 
    ],
    "FJ" => [
        "name" => "Fiji" 
    ],
    "FI" => [
        "name" => "Finland" 
    ],
    "FR" => [
        "name" => "France" 
    ],
    "GF" => [
        "name" => "French Guiana" 
    ],
    "PF" => [
        "name" => "French Polynesia" 
    ],
    "TF" => [
        "name" => "French Southern Territories" 
    ],
    "GE" => [
        "name" => "Georgia" 
    ],
    "DE" => [
        "name" => "Germany" 
    ],
    "GH" => [
        "name" => "Ghana" 
    ],
    "GI" => [
        "name" => "Gibraltar" 
    ],
    "GR" => [
        "name" => "Greece" 
    ],
    "GL" => [
        "name" => "Greenland" 
    ],
    "GU" => [
        "name" => "Guam" 
    ],
    "GT" => [
        "name" => "Guatemala" 
    ],
    "GW" => [
        "name" => "Guinea-Bissau" 
    ],
    "GY" => [
        "name" => "Guyana" 
    ],
    "HT" => [
        "name" => "Haiti" 
    ],
    "HN" => [
        "name" => "Honduras" 
    ],
    "HK" => [
        "name" => "Hong Kong" 
    ],
    "HU" => [
        "name" => "Hungary" 
    ],
    "IS" => [
        "name" => "Iceland" 
    ],
    "IN" => [
        "name" => "India" 
    ],
    "ID" => [
        "name" => "Indonesia" 
    ],
    "IR" => [
        "name" => "Iran" 
    ],
    "IQ" => [
        "name" => "Iraq" 
    ],
    "IE" => [
        "name" => "Ireland" 
    ],
    "IL" => [
        "name" => "Israel" 
    ],
    "IT" => [
        "name" => "Italy" 
    ],
    "JM" => [
        "name" => "Jamaica" 
    ],
    "JP" => [
        "name" => "Japan" 
    ],
    "JO" => [
        "name" => "Jordan" 
    ],
    "KZ" => [
        "name" => "Kazakhstan" 
    ],
    "KE" => [
        "name" => "Kenya" 
    ],
    "KI" => [
        "name" => "Kiribati" 
    ],
    "KG" => [
        "name" => "Kyrgyzstan" 
    ],
    "LV" => [
        "name" => "Latvia" 
    ],
    "LB" => [
        "name" => "Lebanon" 
    ],
    "LR" => [
        "name" => "Liberia" 
    ],
    "LY" => [
        "name" => "Libya" 
    ],
    "LT" => [
        "name" => "Lithuania" 
    ],
    "LU" => [
        "name" => "Luxembourg" 
    ],
    "MO" => [
        "name" => "Macau" 
    ],
    "MK" => [
        "name" => "Macedonia (FYROM)" 
    ],
    "MY" => [
        "name" => "Malaysia" 
    ],
    "MV" => [
        "name" => "Maldives" 
    ],
    "MT" => [
        "name" => "Malta" 
    ],
    "MH" => [
        "name" => "Marshall Islands" 
    ],
    "MQ" => [
        "name" => "Martinique" 
    ],
    "MU" => [
        "name" => "Mauritius" 
    ],
    "MX" => [
        "name" => "Mexico" 
    ],
    "FM" => [
        "name" => "Micronesia" 
    ],
    "MD" => [
        "name" => "Moldova" 
    ],
    "MC" => [
        "name" => "Monaco" 
    ],
    "MN" => [
        "name" => "Mongolia" 
    ],
    "MA" => [
        "name" => "Morocco" 
    ],
    "MZ" => [
        "name" => "Mozambique" 
    ],
    "MM" => [
        "name" => "Myanmar (Burma)" 
    ],
    "NA" => [
        "name" => "Namibia" 
    ],
    "NR" => [
        "name" => "Nauru" 
    ],
    "NP" => [
        "name" => "Nepal" 
    ],
    "NL" => [
        "name" => "Netherlands" 
    ],
    "NC" => [
        "name" => "New Caledonia" 
    ],
    "NZ" => [
        "name" => "New Zealand" 
    ],
    "NI" => [
        "name" => "Nicaragua" 
    ],
    "NG" => [
        "name" => "Nigeria" 
    ],
    "NU" => [
        "name" => "Niue" 
    ],
    "NF" => [
        "name" => "Norfolk Island" 
    ],
    "KP" => [
        "name" => "North Korea" 
    ],
    "MP" => [
        "name" => "Northern Mariana Islands" 
    ],
    "NO" => [
        "name" => "Norway" 
    ],
    "PK" => [
        "name" => "Pakistan" 
    ],
    "PW" => [
        "name" => "Palau" 
    ],
    "PS" => [
        "name" => "Palestine" 
    ],
    "PA" => [
        "name" => "Panama" 
    ],
    "PG" => [
        "name" => "Papua New Guinea" 
    ],
    "PY" => [
        "name" => "Paraguay" 
    ],
    "PE" => [
        "name" => "Peru" 
    ],
    "PH" => [
        "name" => "Philippines" 
    ],
    "PN" => [
        "name" => "Pitcairn Islands" 
    ],
    "PL" => [
        "name" => "Poland" 
    ],
    "PT" => [
        "name" => "Portugal" 
    ],
    "PR" => [
        "name" => "Puerto Rico" 
    ],
    "QA" => [
        "name" => "Qatar" 
    ],
    "RE" => [
        "name" => "Réunion" 
    ],
    "RO" => [
        "name" => "Romania" 
    ],
    "RU" => [
        "name" => "Russia" 
    ],
    "WS" => [
        "name" => "Samoa" 
    ],
    "SM" => [
        "name" => "San Marino" 
    ],
    "SA" => [
        "name" => "Saudi Arabia" 
    ],
    "RS" => [
        "name" => "Serbia" 
    ],
    "SC" => [
        "name" => "Seychelles" 
    ],
    "SG" => [
        "name" => "Singapore" 
    ],
    "SK" => [
        "name" => "Slovakia" 
    ],
    "SI" => [
        "name" => "Slovenia" 
    ],
    "SB" => [
        "name" => "Solomon Islands" 
    ],
    "ZA" => [
        "name" => "South Africa" 
    ],
    "GS" => [
        "name" => "South Georgia & South Sandwich Islands" 
    ],
    "KR" => [
        "name" => "South Korea" 
    ],
    "ES" => [
        "name" => "Spain" 
    ],
    "LK" => [
        "name" => "Sri Lanka" 
    ],
    "PM" => [
        "name" => "St. Pierre & Miquelon" 
    ],
    "SD" => [
        "name" => "Sudan" 
    ],
    "SR" => [
        "name" => "Suriname" 
    ],
    "SJ" => [
        "name" => "Svalbard & Jan Mayen" 
    ],
    "SE" => [
        "name" => "Sweden" 
    ],
    "CH" => [
        "name" => "Switzerland" 
    ],
    "SY" => [
        "name" => "Syria" 
    ],
    "TW" => [
        "name" => "Taiwan" 
    ],
    "TJ" => [
        "name" => "Tajikistan" 
    ],
    "TH" => [
        "name" => "Thailand" 
    ],
    "TL" => [
        "name" => "Timor-Leste" 
    ],
    "TK" => [
        "name" => "Tokelau" 
    ],
    "TO" => [
        "name" => "Tonga" 
    ],
    "TT" => [
        "name" => "Trinidad & Tobago" 
    ],
    "TN" => [
        "name" => "Tunisia" 
    ],
    "TR" => [
        "name" => "Turkey" 
    ],
    "TM" => [
        "name" => "Turkmenistan" 
    ],
    "TC" => [
        "name" => "Turks & Caicos Islands" 
    ],
    "TV" => [
        "name" => "Tuvalu" 
    ],
    "UM" => [
        "name" => "U.S. Outlying Islands" 
    ],
    "UA" => [
        "name" => "Ukraine" 
    ],
    "AE" => [
        "name" => "United Arab Emirates" 
    ],
    "GB" => [
        "name" => "United Kingdom" 
    ],
    "US" => [
        "name" => "United States" 
    ],
    "UY" => [
        "name" => "Uruguay" 
    ],
    "UZ" => [
        "name" => "Uzbekistan" 
    ],
    "VU" => [
        "name" => "Vanuatu" 
    ],
    "VA" => [
        "name" => "Vatican City" 
    ],
    "VE" => [
        "name" => "Venezuela" 
    ],
    "VN" => [
        "name" => "Vietnam" 
    ],
    "WF" => [
        "name" => "Wallis & Futuna" 
    ],
    "EH" => [
        "name" => "Western Sahara" 
    ],
];

// taken from Toland Hon's Answer
function prettyOffset($offset) {
    $offset_prefix = $offset < 0 ? '-' : '+';
    $offset_formatted = gmdate( 'H:i', abs($offset) );

    $pretty_offset = "UTC${offset_prefix}${offset_formatted}";

    return $pretty_offset;
}

foreach ($timezones as $k => $v) {
    $tz = DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $k);

    foreach ($tz as $value) {
        $t = new DateTimeZone($value);
        $offset = (new DateTime("now", $t))->getOffset();
        $timezones[$k]['timezones'][$value] = prettyOffset($offset);
    }   
}

Isso me dá uma matriz agrupada por países:

["US"]=>
  array(2) {
    ["name"]=>
    string(13) "United States"
    ["timezones"]=>
    array(29) {
      ["America/Adak"]=>
      string(9) "UTC-10:00"
      ["America/Anchorage"]=>
      string(9) "UTC-09:00"
      ["America/Boise"]=>
      string(9) "UTC-07:00"
      ["America/Chicago"]=>
      string(9) "UTC-06:00"
      ["America/Denver"]=>
      string(9) "UTC-07:00"
      ["America/Detroit"]=>
      string(9) "UTC-05:00"
      ["America/Indiana/Indianapolis"]=>
      string(9) "UTC-05:00"
      ["America/Indiana/Knox"]=>
      string(9) "UTC-06:00"
      ["America/Indiana/Marengo"]=>
      string(9) "UTC-05:00"
      ["America/Indiana/Petersburg"]=>
      string(9) "UTC-05:00"
      ["America/Indiana/Tell_City"]=>
      string(9) "UTC-06:00"
      ["America/Indiana/Vevay"]=>
      string(9) "UTC-05:00"
      ["America/Indiana/Vincennes"]=>
      string(9) "UTC-05:00"
      ["America/Indiana/Winamac"]=>
      string(9) "UTC-05:00"
      ["America/Juneau"]=>
      string(9) "UTC-09:00"
      ["America/Kentucky/Louisville"]=>
      string(9) "UTC-05:00"
      ["America/Kentucky/Monticello"]=>
      string(9) "UTC-05:00"
      ["America/Los_Angeles"]=>
      string(9) "UTC-08:00"
      ["America/Menominee"]=>
      string(9) "UTC-06:00"
      ["America/Metlakatla"]=>
      string(9) "UTC-08:00"
      ["America/New_York"]=>
      string(9) "UTC-05:00"
      ["America/Nome"]=>
      string(9) "UTC-09:00"
      ["America/North_Dakota/Beulah"]=>
      string(9) "UTC-06:00"
      ["America/North_Dakota/Center"]=>
      string(9) "UTC-06:00"
      ["America/North_Dakota/New_Salem"]=>
      string(9) "UTC-06:00"
      ["America/Phoenix"]=>
      string(9) "UTC-07:00"
      ["America/Sitka"]=>
      string(9) "UTC-09:00"
      ["America/Yakutat"]=>
      string(9) "UTC-09:00"
      ["Pacific/Honolulu"]=>
      string(9) "UTC-10:00"
    }
  }

O que significa que agora eu posso fazer algo como abaixo (é claro, com alguns truques javaScript): Configurações de fuso horário do Google Analytics


2
Hey @Lucky, você poderia me dizer como fez isso? Eu não consigo entender isso pelo seu asnwer.
Lal

1

Em alguns projetos, realmente não faz sentido ter os fusos horários detalhados da África, Europa ou Pacífico. Então aqui está uma versão curta

$timezoneTable = array(
    "-12" => "(GMT -12:00) Eniwetok, Kwajalein",
    "-11" => "(GMT -11:00) Midway Island, Samoa",
    "-10" => "(GMT -10:00) Hawaii",
    "-9" => "(GMT -9:00) Alaska",
    "-8" => "(GMT -8:00) Pacific Time (US &amp; Canada)",
    "-7" => "(GMT -7:00) Mountain Time (US &amp; Canada)",
    "-6" => "(GMT -6:00) Central Time (US &amp; Canada), Mexico City",
    "-5" => "(GMT -5:00) Eastern Time (US &amp; Canada), Bogota, Lima",
    "-4" => "(GMT -4:00) Atlantic Time (Canada), Caracas, La Paz",
    "-3.5" => "(GMT -3:30) Newfoundland",
    "-3" => "(GMT -3:00) Brazil, Buenos Aires, Georgetown",
    "-2" => "(GMT -2:00) Mid-Atlantic",
    "-1" => "(GMT -1:00) Azores, Cape Verde Islands",
    "0" => "(GMT) Western Europe Time, London, Lisbon, Casablanca",
    "1" => "(GMT +1:00) Brussels, Copenhagen, Madrid, Paris",
    "2" => "(GMT +2:00) Kaliningrad, South Africa",
    "3" => "(GMT +3:00) Baghdad, Riyadh, Moscow, St. Petersburg",
    "3.5" => "(GMT +3:30) Tehran",
    "4" => "(GMT +4:00) Abu Dhabi, Muscat, Baku, Tbilisi",
    "4.5" => "(GMT +4:30) Kabul",
    "5" => "(GMT +5:00) Ekaterinburg, Islamabad, Karachi, Tashkent",
    "5.5" => "(GMT +5:30) Bombay, Calcutta, Madras, New Delhi",
    "6" => "(GMT +6:00) Almaty, Dhaka, Colombo",
    "7" => "(GMT +7:00) Bangkok, Hanoi, Jakarta",
    "8" => "(GMT +8:00) Beijing, Perth, Singapore, Hong Kong",
    "9" => "(GMT +9:00) Tokyo, Seoul, Osaka, Sapporo, Yakutsk",
    "9.5" => "(GMT +9:30) Adelaide, Darwin",
    "10" => "(GMT +10:00) Eastern Australia, Guam, Vladivostok",
    "11" => "(GMT +11:00) Magadan, Solomon Islands, New Caledonia",
    "12" => "(GMT +12:00) Auckland, Wellington, Fiji, Kamchatka"
);

echo "<select>";
foreach ($timezoneTable as $k => $v){
    $sel = ($k==-5)?" selected":"";
    echo "<option value='".$k."'".$sel.">".$v."</option>";
}
echo "</select>" 

isso irá gerar uma seleção como abaixo:

insira a descrição da imagem aqui


1
public static function tzList()
{
    $tzMap = array();
    $zones = \DateTimeZone::listIdentifiers();
    foreach ($zones as $zone) {
        $tz = new \DateTimeZone($zone);
        $now = new \DateTime("utc", $tz);
        $diffInSeconds = $tz->getOffset($now);
        $hours = floor($diffInSeconds / 3600);
        $minutes = floor(($diffInSeconds % 3600) / 60);
        $tzMap[$zone] = sprintf("%+d", $hours) . ":" . sprintf("%02d", $minutes);
    }
    return $tzMap;
}

Tada! É simples assim. Fornece uma matriz com a chave como fuso horário do PHP e o valor como uma sequência no formato + -Hours: Minutes


1

Eu criei uma classe PHP para isso com um plugin jQuery correspondente. Eu o código aberto em https://github.com/peterjtracey/timezoneWidget - o código PHP é inspirado por outra resposta de stackoverflow, mas acho muito mais elegante. O plugin jQuery fornece uma ótima interface para selecionar um fuso horário.


1

Variante 1

Resultado:

...
[America/Scoresbysund] => (UTC+00:00) America/Scoresbysund
[Atlantic/Azores] => (UTC+00:00) Atlantic/Azores
[Atlantic/Reykjavik] => (UTC+00:00) Atlantic/Reykjavik
[Atlantic/St_Helena] => (UTC+00:00) Atlantic/St_Helena
[UTC] => (UTC+00:00) UTC
[Africa/Algiers] => (UTC+01:00) Africa/Algiers
[Africa/Bangui] => (UTC+01:00) Africa/Bangui 
...

Código:

$tzlist = DateTimeZone::listIdentifiers(DateTimeZone::ALL);

$result = [];
foreach ($tzlist as $timezone) {
    $offset = (new DateTimeZone($timezone))->getOffset(new DateTime);
    $offsetPrefix = $offset < 0 ? '-' : '+';
    $offsetFormatted = gmdate('H:i', abs($offset));
    $utcOffset = "(UTC$offsetPrefix$offsetFormatted)";

    $result[$timezone] = "${$utcOffset} $timezone";
}
asort($result);
print_r($result);

Variante 2

Resultado:

Array
(
    [0] => Array
        (
            [value] => Africa/Abidjan
            [offset] => +00:00
            [text] => (UTC+00:00) Africa/Abidjan
        )

    [1] => Array
        (
            [value] => Africa/Conakry
            [offset] => +00:00
            [text] => (UTC+00:00) Africa/Conakry
        )
...

Código:

$tzlist = DateTimeZone::listIdentifiers(DateTimeZone::ALL);

$result = [];
foreach ($tzlist as $timezone) {
    $offset = (new DateTimeZone($timezone))->getOffset(new DateTime);
    $offsetPrefix = $offset < 0 ? '-' : '+';
    $offsetFormatted = gmdate('H:i', abs($offset));
    $utcOffset = "UTC$offsetPrefix$offsetFormatted";

    $result[] = [
        'value' => $timezone,
        'offset' => "$offsetPrefix$offsetFormatted"
        // "text" => "($utcOffset) $timezone"
    ];
}
usort($result, function ($a, $b) { return strcmp($a["offset"], $b["offset"]); });
print_r($result);

0

a primeira opção permitiria que você pegasse o valor de $ _POST ['qualquer coisa que você chamar'] e o adicionasse ao UTC. ou mesmo armazene esse valor e sempre chame UTC + userTZsetting sempre que precisar mais tarde. parece mais fácil para mim. a última opção seria muito mais valiosa se os fusos horários mudassem com frequência.


0

Nenhum deles. Em vez disso, prepare uma matriz em PHP com esses fusos horários. Gostar

$arr[0] = "(GMT+02:00) Harare, Pretoria";
$arr[1] = "(GMT+03:00) Jerusalem";

ou

$arr[0] = array("America/Campo_Grande", "(GMT+02:00) Harare, Pretoria");
$arr[1] = array("America/Israel", "(GMT+03:00) Jerusalem");

e assim por diante. Em seguida, gere o formulário com base nesta matriz:

foreach ($arr as $k => $v)
   $str .= "<option value=$k>$v[1]</option>";

E então você pode alternar facilmente com diferentes formatos com apenas uma modificação de código na linha acima. A validação também será muito mais fácil e não exigirá expressões regulares. Basta comparar o valor enviado por POST ou GET com uma matriz. Agora é fácil definir $ arr [$ value_sent_by_form] [0] mantém um valor compatível com PHP, enquanto $ arr [$ value_sent_by_form] [1] valor amigável.


Como você saberia o fuso horário UTC para definir se os únicos valores que você possui são uma chave numérica e uma sequência amigável para humanos? Eu acho que você pretende definir as chaves da matriz para os valores reais, como na lista um. Além disso, o que eu escolher, você pode ter certeza de que ele encontrará o caminho para uma matriz PHP. ;)
Xeoncross

Em seguida, prepare o array assim: $ arr [0] = array ("America / Campo_Grande", "(GMT + 02: 00) Harare, Pretória");
doc

0

Veja também este exemplo

<?php
     function get_timezones() 
     {
        $o = array();
        $t_zones = timezone_identifiers_list();
        foreach($t_zones as $a)
        {
            $t = '';

            try
            {
                //this throws exception for 'US/Pacific-New'
                $zone = new DateTimeZone($a);

                $seconds = $zone->getOffset( new DateTime("now" , $zone) );
                $hours = sprintf( "%+02d" , intval($seconds/3600));
                $minutes = sprintf( "%02d" , ($seconds%3600)/60 );

                $t = $a ."  [ $hours:$minutes ]" ;

                $o[$a] = $t;
            }

            //exceptions must be catched, else a blank page
            catch(Exception $e)
            {
                //die("Exception : " . $e->getMessage() . '<br />');
                //what to do in catch ? , nothing just relax
            }
        }

        ksort($o);

        return $o;
    } 

    $o = get_timezones();
    ?>

    <html>
    <body>
    <select name="time_zone">
    <?php
        foreach($o as $tz => $label)
        {
            echo "<option value="$tz">$label</option>";
        }
    ?>
    </select>
    </body>
    </html>

0

Depois de tentar todas as soluções apresentadas aqui e não estar satisfeito, encontrei um script que corresponde às minhas necessidades e é mais amigável. Para o registro, vou salvá-lo como uma possível solução. Adoro as soluções copiar / colar :)

O script retorna uma seleção com o fuso horário que você deseja pré-selecionado.

insira a descrição da imagem aqui

Fonte: https://e-tel.eu/2011/07/13/create-a-time-zone-drop-down-list-ddl-in-php/

<?php
/**
 * returns a HTML formated TimeZone select
 *
 * PHP 5 >= 5.2.0
 * 
 * @param $selectedTimeZone string The timezone marked as "selected"
 * @return string
 */
function displayTimeZoneSelect($selectedTimeZone = 'America/New_York'){
    $countryCodes = getCountryCodes();
    $return = null;
    foreach ($countryCodes as $country => $countryCode) {
        $timezone_identifiers = DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY,$countryCode);
        foreach( $timezone_identifiers as $value ){
            /* getTimeZoneOffset returns minutes and we need to display hours */
            $offset = getTimeZoneOffset($value)/60;
            /* for the GMT+1 GMT-1 display */
            $offset = ( substr($offset,0,1) == "-" ? " (GMT" : " (GMT+" ) . $offset . ")";
            /* America/New_York -> America/New York */
            $displayValue = (str_replace('_',' ',$value));
            /* Find the city */
            $ex = explode("/",$displayValue);
            $city = ( ($ex[2]) ? $ex[2] : $ex[1] );
            /* For the special names */
            $displayValue = htmlentities($country." - ".$city.$offset); 
            /* handle the $selectedTimeZone in the select form */
            $selected = ( ($value == $selectedTimeZone) ? ' selected="selected"' : null );
            $return .= '<option value="' . $value . '"' . $selected . '>'
                . $displayValue
                . '</option>' . PHP_EOL;
        }
    }

    return $return;
}

/**
 * ISO 3166 code list
 *
 * @return array The country codes in 'COUNTRY' => 'CODE' format
 * @link http://www.iso.org/iso/iso_3166_code_lists ISO Website
 */
function getCountryCodes(){
$return = array(
"AFGHANISTAN"=>"AF",
"ALAND ISLANDS"=>"AX",
"ALBANIA"=>"AL",
"ALGERIA"=>"DZ",
"AMERICAN SAMOA"=>"AS",
"ANDORRA"=>"AD",
"ANGOLA"=>"AO",
"ANGUILLA"=>"AI",
"ANTARCTICA"=>"AQ",
"ANTIGUA AND BARBUDA"=>"AG",
"ARGENTINA"=>"AR",
"ARMENIA"=>"AM",
"ARUBA"=>"AW",
"AUSTRALIA"=>"AU",
"AUSTRIA"=>"AT",
"AZERBAIJAN"=>"AZ",
"BAHAMAS"=>"BS",
"BAHRAIN"=>"BH",
"BANGLADESH"=>"BD",
"BARBADOS"=>"BB",
"BELARUS"=>"BY",
"BELGIUM"=>"BE",
"BELIZE"=>"BZ",
"BENIN"=>"BJ",
"BERMUDA"=>"BM",
"BHUTAN"=>"BT",
"BOLIVIA, PLURINATIONAL STATE OF"=>"BO",
"BONAIRE, SINT EUSTATIUS AND SABA"=>"BQ",
"BOSNIA AND HERZEGOVINA"=>"BA",
"BOTSWANA"=>"BW",
"BOUVET ISLAND"=>"BV",
"BRAZIL"=>"BR",
"BRITISH INDIAN OCEAN TERRITORY"=>"IO",
"BRUNEI DARUSSALAM"=>"BN",
"BULGARIA"=>"BG",
"BURKINA FASO"=>"BF",
"BURUNDI"=>"BI",
"CAMBODIA"=>"KH",
"CAMEROON"=>"CM",
"CANADA"=>"CA",
"CAPE VERDE"=>"CV",
"CAYMAN ISLANDS"=>"KY",
"CENTRAL AFRICAN REPUBLIC"=>"CF",
"CHAD"=>"TD",
"CHILE"=>"CL",
"CHINA"=>"CN",
"CHRISTMAS ISLAND"=>"CX",
"COCOS (KEELING) ISLANDS"=>"CC",
"COLOMBIA"=>"CO",
"COMOROS"=>"KM",
"CONGO"=>"CG",
"CONGO, THE DEMOCRATIC REPUBLIC OF THE"=>"CD",
"COOK ISLANDS"=>"CK",
"COSTA RICA"=>"CR",
"CÔTE D'IVOIRE"=>"CI",
"CROATIA"=>"HR",
"CUBA"=>"CU",
"CURAÇAO"=>"CW",
"CYPRUS"=>"CY",
"CZECH REPUBLIC"=>"CZ",
"DENMARK"=>"DK",
"DJIBOUTI"=>"DJ",
"DOMINICA"=>"DM",
"DOMINICAN REPUBLIC"=>"DO",
"ECUADOR"=>"EC",
"EGYPT"=>"EG",
"EL SALVADOR"=>"SV",
"EQUATORIAL GUINEA"=>"GQ",
"ERITREA"=>"ER",
"ESTONIA"=>"EE",
"ETHIOPIA"=>"ET",
"FALKLAND ISLANDS (MALVINAS)"=>"FK",
"FAROE ISLANDS"=>"FO",
"FIJI"=>"FJ",
"FINLAND"=>"FI",
"FRANCE"=>"FR",
"FRENCH GUIANA"=>"GF",
"FRENCH POLYNESIA"=>"PF",
"FRENCH SOUTHERN TERRITORIES"=>"TF",
"GABON"=>"GA",
"GAMBIA"=>"GM",
"GEORGIA"=>"GE",
"GERMANY"=>"DE",
"GHANA"=>"GH",
"GIBRALTAR"=>"GI",
"GREECE"=>"GR",
"GREENLAND"=>"GL",
"GRENADA"=>"GD",
"GUADELOUPE"=>"GP",
"GUAM"=>"GU",
"GUATEMALA"=>"GT",
"GUERNSEY"=>"GG",
"GUINEA"=>"GN",
"GUINEA-BISSAU"=>"GW",
"GUYANA"=>"GY",
"HAITI"=>"HT",
"HEARD ISLAND AND MCDONALD ISLANDS"=>"HM",
"HOLY SEE (VATICAN CITY STATE)"=>"VA",
"HONDURAS"=>"HN",
"HONG KONG"=>"HK",
"HUNGARY"=>"HU",
"ICELAND"=>"IS",
"INDIA"=>"IN",
"INDONESIA"=>"ID",
"IRAN, ISLAMIC REPUBLIC OF"=>"IR",
"IRAQ"=>"IQ",
"IRELAND"=>"IE",
"ISLE OF MAN"=>"IM",
"ISRAEL"=>"IL",
"ITALY"=>"IT",
"JAMAICA"=>"JM",
"JAPAN"=>"JP",
"JERSEY"=>"JE",
"JORDAN"=>"JO",
"KAZAKHSTAN"=>"KZ",
"KENYA"=>"KE",
"KIRIBATI"=>"KI",
"KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF"=>"KP",
"KOREA, REPUBLIC OF"=>"KR",
"KUWAIT"=>"KW",
"KYRGYZSTAN"=>"KG",
"LAO PEOPLE'S DEMOCRATIC REPUBLIC"=>"LA",
"LATVIA"=>"LV",
"LEBANON"=>"LB",
"LESOTHO"=>"LS",
"LIBERIA"=>"LR",
"LIBYAN ARAB JAMAHIRIYA"=>"LY",
"LIECHTENSTEIN"=>"LI",
"LITHUANIA"=>"LT",
"LUXEMBOURG"=>"LU",
"MACAO"=>"MO",
"MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF"=>"MK",
"MADAGASCAR"=>"MG",
"MALAWI"=>"MW",
"MALAYSIA"=>"MY",
"MALDIVES"=>"MV",
"MALI"=>"ML",
"MALTA"=>"MT",
"MARSHALL ISLANDS"=>"MH",
"MARTINIQUE"=>"MQ",
"MAURITANIA"=>"MR",
"MAURITIUS"=>"MU",
"MAYOTTE"=>"YT",
"MEXICO"=>"MX",
"MICRONESIA, FEDERATED STATES OF"=>"FM",
"MOLDOVA, REPUBLIC OF"=>"MD",
"MONACO"=>"MC",
"MONGOLIA"=>"MN",
"MONTENEGRO"=>"ME",
"MONTSERRAT"=>"MS",
"MOROCCO"=>"MA",
"MOZAMBIQUE"=>"MZ",
"MYANMAR"=>"MM",
"NAMIBIA"=>"NA",
"NAURU"=>"NR",
"NEPAL"=>"NP",
"NETHERLANDS"=>"NL",
"NEW CALEDONIA"=>"NC",
"NEW ZEALAND"=>"NZ",
"NICARAGUA"=>"NI",
"NIGER"=>"NE",
"NIGERIA"=>"NG",
"NIUE"=>"NU",
"NORFOLK ISLAND"=>"NF",
"NORTHERN MARIANA ISLANDS"=>"MP",
"NORWAY"=>"NO",
"OMAN"=>"OM",
"PAKISTAN"=>"PK",
"PALAU"=>"PW",
"PALESTINIAN TERRITORY, OCCUPIED"=>"PS",
"PANAMA"=>"PA",
"PAPUA NEW GUINEA"=>"PG",
"PARAGUAY"=>"PY",
"PERU"=>"PE",
"PHILIPPINES"=>"PH",
"PITCAIRN"=>"PN",
"POLAND"=>"PL",
"PORTUGAL"=>"PT",
"PUERTO RICO"=>"PR",
"QATAR"=>"QA",
"RÉUNION"=>"RE",
"ROMANIA"=>"RO",
"RUSSIAN FEDERATION"=>"RU",
"RWANDA"=>"RW",
"SAINT BARTHÉLEMY"=>"BL",
"SAINT HELENA, ASCENSION AND TRISTAN DA CUNHA"=>"SH",
"SAINT KITTS AND NEVIS"=>"KN",
"SAINT LUCIA"=>"LC",
"SAINT MARTIN (FRENCH PART)"=>"MF",
"SAINT PIERRE AND MIQUELON"=>"PM",
"SAINT VINCENT AND THE GRENADINES"=>"VC",
"SAMOA"=>"WS",
"SAN MARINO"=>"SM",
"SAO TOME AND PRINCIPE"=>"ST",
"SAUDI ARABIA"=>"SA",
"SENEGAL"=>"SN",
"SERBIA"=>"RS",
"SEYCHELLES"=>"SC",
"SIERRA LEONE"=>"SL",
"SINGAPORE"=>"SG",
"SINT MAARTEN (DUTCH PART)"=>"SX",
"SLOVAKIA"=>"SK",
"SLOVENIA"=>"SI",
"SOLOMON ISLANDS"=>"SB",
"SOMALIA"=>"SO",
"SOUTH AFRICA"=>"ZA",
"SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS"=>"GS",
"SPAIN"=>"ES",
"SRI LANKA"=>"LK",
"SUDAN"=>"SD",
"SURINAME"=>"SR",
"SVALBARD AND JAN MAYEN"=>"SJ",
"SWAZILAND"=>"SZ",
"SWEDEN"=>"SE",
"SWITZERLAND"=>"CH",
"SYRIAN ARAB REPUBLIC"=>"SY",
"TAIWAN, PROVINCE OF CHINA"=>"TW",
"TAJIKISTAN"=>"TJ",
"TANZANIA, UNITED REPUBLIC OF"=>"TZ",
"THAILAND"=>"TH",
"TIMOR-LESTE"=>"TL",
"TOGO"=>"TG",
"TOKELAU"=>"TK",
"TONGA"=>"TO",
"TRINIDAD AND TOBAGO"=>"TT",
"TUNISIA"=>"TN",
"TURKEY"=>"TR",
"TURKMENISTAN"=>"TM",
"TURKS AND CAICOS ISLANDS"=>"TC",
"TUVALU"=>"TV",
"UGANDA"=>"UG",
"UKRAINE"=>"UA",
"UNITED ARAB EMIRATES"=>"AE",
"UNITED KINGDOM"=>"GB",
"UNITED STATES"=>"US",
"UNITED STATES MINOR OUTLYING ISLANDS"=>"UM",
"URUGUAY"=>"UY",
"UZBEKISTAN"=>"UZ",
"VANUATU"=>"VU",
"VENEZUELA, BOLIVARIAN REPUBLIC OF"=>"VE",
"VIET NAM"=>"VN",
"VIRGIN ISLANDS, BRITISH"=>"VG",
"VIRGIN ISLANDS, U.S."=>"VI",
"WALLIS AND FUTUNA"=>"WF",
"WESTERN SAHARA"=>"EH",
"YEMEN"=>"YE",
"ZAMBIA"=>"ZM",
"ZIMBABWE"=>"ZW");
return $return;
}

/**
 * Calculates the offset from UTC for a given timezone
 *
 * @return integer
 */
function getTimeZoneOffset($timeZone) {
    $dateTimeZoneUTC = new DateTimeZone("UTC");
    $dateTimeZoneCurrent = new DateTimeZone($timeZone);

    $dateTimeUTC = new DateTime("now",$dateTimeZoneUTC);
    $dateTimeCurrent = new DateTime("now",$dateTimeZoneCurrent);

    $offset = (($dateTimeZoneCurrent->getOffset($dateTimeUTC))/60);
    return $offset;
}
?>


    <label for="timeZone">Timezone<br />
        <select id="timeZone" name="timeZone">
            <?php echo displayTimeZoneSelect("America/Toronto");?>
        </select>
    </label>

0

Aqui está uma aula que eu montei, misturando o que eu achava que era a melhor de todas as sugestões aqui e com o Carbon como uma dependência:

namespace App\Support;

use Carbon\Carbon;
use DateTimeZone;

class Timezone
{
    protected static $timezones;

    public static function all(): array
    {
        if (static::$timezones) {
            return static::$timezones;
        }

        $offsets   = [];
        $timezones = [];

        foreach (DateTimeZone::listIdentifiers() as $timezone) {

            $offsets[]            = $offset = Carbon::now()->timezone($timezone)->offset;
            $timezones[$timezone] = static::formatTimezoneDisplay($timezone, $offset);

            array_multisort($offsets, $timezones);

        }

        return static::$timezones = $timezones;
    }

    protected static function formatTimezoneDisplay(string $timezone, string $offset): string
    {
        return static::formatOffset($offset) . ' (' . static::formatTimezone($timezone) . ')';
    }

    protected static function formatOffset(string $offset): string
    {
        if (!$offset) {
            return 'UTC±00:00';
        }

        $hours   = intval($offset / 3600);
        $minutes = abs(intval($offset % 3600 / 60));

        return 'UTC' . sprintf('%+03d:%02d', $hours, $minutes);
    }

    protected static function formatTimezone(string $timezone): string
    {
        return str_replace(['/', '_', 'St '], [', ', ' ', 'St. '], $timezone);
    }
}

Você simplesmente Timezone:all(), e isso gera uma matriz no formato de UTC-5:00 (America, New York), para que você possa exibir facilmente um campo de seleção no seu front-end.


0

Para aqueles que usam o CodeIgniter, há uma função incorporada do Date Helper chamada timezone_menu . Estes:

$this->load->helper('date');
echo timezone_menu('GMT', 'form-control', 'dropdown-name', ['id' => 'ci-timezone']);

Produza a seguinte saída:

<select name="dropdown-name" class="form-control" id="ci-timezone">
  <option value="UM12">(UTC -12:00) Baker/Howland Island</option>
  <option value="UM11">(UTC -11:00) Niue</option>
  <option value="UM10">(UTC -10:00) Hawaii-Aleutian Standard Time, Cook Islands, Tahiti</option>
  <option value="UM95">(UTC -9:30) Marquesas Islands</option>
  <option value="UM9">(UTC -9:00) Alaska Standard Time, Gambier Islands</option>
  <option value="UM8">(UTC -8:00) Pacific Standard Time, Clipperton Island</option>
  <option value="UM7">(UTC -7:00) Mountain Standard Time</option>
  <option value="UM6">(UTC -6:00) Central Standard Time</option>
  <option value="UM5">(UTC -5:00) Eastern Standard Time, Western Caribbean Standard Time</option>
  <option value="UM45">(UTC -4:30) Venezuelan Standard Time</option>
  <option value="UM4">(UTC -4:00) Atlantic Standard Time, Eastern Caribbean Standard Time</option>
  <option value="UM35">(UTC -3:30) Newfoundland Standard Time</option>
  <option value="UM3">(UTC -3:00) Argentina, Brazil, French Guiana, Uruguay</option>
  <option value="UM2">(UTC -2:00) South Georgia/South Sandwich Islands</option>
  <option value="UM1">(UTC -1:00) Azores, Cape Verde Islands</option>
  <option value="UTC" selected="selected">(UTC) Greenwich Mean Time, Western European Time</option>
  <option value="UP1">(UTC +1:00) Central European Time, West Africa Time</option>
  <option value="UP2">(UTC +2:00) Central Africa Time, Eastern European Time, Kaliningrad Time</option>
  <option value="UP3">(UTC +3:00) Moscow Time, East Africa Time, Arabia Standard Time</option>
  <option value="UP35">(UTC +3:30) Iran Standard Time</option>
  <option value="UP4">(UTC +4:00) Azerbaijan Standard Time, Samara Time</option>
  <option value="UP45">(UTC +4:30) Afghanistan</option>
  <option value="UP5">(UTC +5:00) Pakistan Standard Time, Yekaterinburg Time</option>
  <option value="UP55">(UTC +5:30) Indian Standard Time, Sri Lanka Time</option>
  <option value="UP575">(UTC +5:45) Nepal Time</option>
  <option value="UP6">(UTC +6:00) Bangladesh Standard Time, Bhutan Time, Omsk Time</option>
  <option value="UP65">(UTC +6:30) Cocos Islands, Myanmar</option>
  <option value="UP7">(UTC +7:00) Krasnoyarsk Time, Cambodia, Laos, Thailand, Vietnam</option>
  <option value="UP8">(UTC +8:00) Australian Western Standard Time, Beijing Time, Irkutsk Time</option>
  <option value="UP875">(UTC +8:45) Australian Central Western Standard Time</option>
  <option value="UP9">(UTC +9:00) Japan Standard Time, Korea Standard Time, Yakutsk Time</option>
  <option value="UP95">(UTC +9:30) Australian Central Standard Time</option>
  <option value="UP10">(UTC +10:00) Australian Eastern Standard Time, Vladivostok Time</option>
  <option value="UP105">(UTC +10:30) Lord Howe Island</option>
  <option value="UP11">(UTC +11:00) Srednekolymsk Time, Solomon Islands, Vanuatu</option>
  <option value="UP115">(UTC +11:30) Norfolk Island</option>
  <option value="UP12">(UTC +12:00) Fiji, Gilbert Islands, Kamchatka Time, New Zealand Standard Time</option>
  <option value="UP1275">(UTC +12:45) Chatham Islands Standard Time</option>
  <option value="UP13">(UTC +13:00) Samoa Time Zone, Phoenix Islands Time, Tonga</option>
  <option value="UP14">(UTC +14:00) Line Islands</option>
</select>

0

Eu fiz isso:

php -r "echo json_encode(array_combine(DateTimeZone::listIdentifiers(DateTimeZone::ALL), DateTimeZone::listIdentifiers(DateTimeZone::ALL)));" > list-of-timezones.json


0

Gostaria de deixar aqui essa ideia:

/*----------TIME ZONE LIST---------*/
function TZList($data_type = false){
    $_all_timezone_identifiers = DateTimeZone::listIdentifiers(DateTimeZone::ALL);
    $TIMEZONE_LIST = array();
    foreach($_all_timezone_identifiers as $k => $v){
        $_tzone_group = explode("/", $_all_timezone_identifiers[$k])[0];

        $_tzone_new = new DateTimeZone($_all_timezone_identifiers[$k]);
        $_tzone_new_date = new DateTime("now", $_tzone_new);

        $tzone_arr = array(
                            'timezone' => $_all_timezone_identifiers[$k],
                            'timediff' => $_tzone_new_date->format('P'),
                            'timezone_offset' => $_tzone_new_date->format('Z')/60, //minutes
                            'text' => "(GMT" .$_tzone_new_date->format('P') .") " .$_all_timezone_identifiers[$k]
                            );

        //BY CONTINENT
        if($data_type === true) $TIMEZONE_LIST[$_tzone_group][] = $tzone_arr; else $TIMEZONE_LIST[] = $tzone_arr;
    }

    //BY TIMEZONE: "America/New_York"
    if(is_string($data_type)){
        $key = array_search($data_type, array_column($TIMEZONE_LIST, 'timezone'));
        $TIMEZONE_LIST = $key !== false ? $TIMEZONE_LIST[$key] : null;
    }

    return $TIMEZONE_LIST;
}
/*--------------------------------*/

Obrigado.


1
Você pode explicar o que isso produz, ou por que é melhor do que qualquer outra resposta?
Vincent

0

País da América - Hora com a lista de fusos horários em formato de matriz.

$america_timezones_list = array(
        '+00:00||America/Danmarkshavn'=>'(+00:00) Danmarkshavn',
        '-01:00||America/Scoresbysund'=>'(-01:00) Scoresbysund',
        '-02:00||America/Miquelon'=>'(-02:00) Miquelon',
        '-02:00||America/Noronha'=>'(-02:00) Noronha',
        '-02:30||America/St_Johns'=>'(-02:30) St_Johns',
        '-03:00||America/Araguaina'=>'(-03:00) Araguaina',
        '-03:00||America/Argentina/Buenos_Aires'=>'(-03:00) Argentina/Buenos_Aires',
        '-03:00||America/Argentina/Catamarca'=>'(-03:00) Argentina/Catamarca',
        '-03:00||America/Argentina/Cordoba'=>'(-03:00) Argentina/Cordoba',
        '-03:00||America/Argentina/Jujuy'=>'(-03:00) Argentina/Jujuy',
        '-03:00||America/Argentina/La_Rioja'=>'(-03:00) Argentina/La_Rioja',
        '-03:00||America/Argentina/Mendoza'=>'(-03:00) Argentina/Mendoza',
        '-03:00||America/Argentina/Rio_Gallegos'=>'(-03:00) Argentina/Rio_Gallegos',
        '-03:00||America/Argentina/Salta'=>'(-03:00) Argentina/Salta',
        '-03:00||America/Argentina/San_Juan'=>'(-03:00) Argentina/San_Juan',
        '-03:00||America/Argentina/San_Luis'=>'(-03:00) Argentina/San_Luis',
        '-03:00||America/Argentina/Tucuman'=>'(-03:00) Argentina/Tucuman',
        '-03:00||America/Argentina/Ushuaia'=>'(-03:00) Argentina/Ushuaia',
        '-03:00||America/Asuncion'=>'(-03:00) Asuncion',
        '-03:00||America/Bahia'=>'(-03:00) Bahia',
        '-03:00||America/Belem'=>'(-03:00) Belem',
        '-03:00||America/Cayenne'=>'(-03:00) Cayenne',
        '-03:00||America/Fortaleza'=>'(-03:00) Fortaleza',
        '-03:00||America/Glace_Bay'=>'(-03:00) Glace_Bay',
        '-03:00||America/Godthab'=>'(-03:00) Godthab',
        '-03:00||America/Goose_Bay'=>'(-03:00) Goose_Bay',
        '-03:00||America/Halifax'=>'(-03:00) Halifax',
        '-03:00||America/Maceio'=>'(-03:00) Maceio',
        '-03:00||America/Moncton'=>'(-03:00) Moncton',
        '-03:00||America/Montevideo'=>'(-03:00) Montevideo',
        '-03:00||America/Paramaribo'=>'(-03:00) Paramaribo',
        '-03:00||America/Punta_Arenas'=>'(-03:00) Punta_Arenas',
        '-03:00||America/Recife'=>'(-03:00) Recife',
        '-03:00||America/Santarem'=>'(-03:00) Santarem',
        '-03:00||America/Santiago'=>'(-03:00) Santiago',
        '-03:00||America/Sao_Paulo'=>'(-03:00) Sao_Paulo',
        '-03:00||America/Thule'=>'(-03:00) Thule',
        '-04:00||America/Anguilla'=>'(-04:00) Anguilla',
        '-04:00||America/Antigua'=>'(-04:00) Antigua',
        '-04:00||America/Aruba'=>'(-04:00) Aruba',
        '-04:00||America/Barbados'=>'(-04:00) Barbados',
        '-04:00||America/Blanc-Sablon'=>'(-04:00) Blanc-Sablon',
        '-04:00||America/Boa_Vista'=>'(-04:00) Boa_Vista',
        '-04:00||America/Campo_Grande'=>'(-04:00) Campo_Grande',
        '-04:00||America/Caracas'=>'(-04:00) Caracas',
        '-04:00||America/Cuiaba'=>'(-04:00) Cuiaba',
        '-04:00||America/Curacao'=>'(-04:00) Curacao',
        '-04:00||America/Detroit'=>'(-04:00) Detroit',
        '-04:00||America/Dominica'=>'(-04:00) Dominica',
        '-04:00||America/Grand_Turk'=>'(-04:00) Grand_Turk',
        '-04:00||America/Grenada'=>'(-04:00) Grenada',
        '-04:00||America/Guadeloupe'=>'(-04:00) Guadeloupe',
        '-04:00||America/Guyana'=>'(-04:00) Guyana',
        '-04:00||America/Havana'=>'(-04:00) Havana',
        '-04:00||America/Indiana/Indianapolis'=>'(-04:00) Indiana/Indianapolis',
        '-04:00||America/Indiana/Marengo'=>'(-04:00) Indiana/Marengo',
        '-04:00||America/Indiana/Petersburg'=>'(-04:00) Indiana/Petersburg',
        '-04:00||America/Indiana/Vevay'=>'(-04:00) Indiana/Vevay',
        '-04:00||America/Indiana/Vincennes'=>'(-04:00) Indiana/Vincennes',
        '-04:00||America/Indiana/Winamac'=>'(-04:00) Indiana/Winamac',
        '-04:00||America/Iqaluit'=>'(-04:00) Iqaluit',
        '-04:00||America/Kentucky/Louisville'=>'(-04:00) Kentucky/Louisville',
        '-04:00||America/Kentucky/Monticello'=>'(-04:00) Kentucky/Monticello',
        '-04:00||America/Kralendijk'=>'(-04:00) Kralendijk',
        '-04:00||America/La_Paz'=>'(-04:00) La_Paz',
        '-04:00||America/Lower_Princes'=>'(-04:00) Lower_Princes',
        '-04:00||America/Manaus'=>'(-04:00) Manaus',
        '-04:00||America/Marigot'=>'(-04:00) Marigot',
        '-04:00||America/Martinique'=>'(-04:00) Martinique',
        '-04:00||America/Montserrat'=>'(-04:00) Montserrat',
        '-04:00||America/Nassau'=>'(-04:00) Nassau',
        '-04:00||America/New_York'=>'(-04:00) New_York',
        '-04:00||America/Nipigon'=>'(-04:00) Nipigon',
        '-04:00||America/Pangnirtung'=>'(-04:00) Pangnirtung',
        '-04:00||America/Port-au-Prince'=>'(-04:00) Port-au-Prince',
        '-04:00||America/Port_of_Spain'=>'(-04:00) Port_of_Spain',
        '-04:00||America/Porto_Velho'=>'(-04:00) Porto_Velho',
        '-04:00||America/Puerto_Rico'=>'(-04:00) Puerto_Rico',
        '-04:00||America/Santo_Domingo'=>'(-04:00) Santo_Domingo',
        '-04:00||America/St_Barthelemy'=>'(-04:00) St_Barthelemy',
        '-04:00||America/St_Kitts'=>'(-04:00) St_Kitts',
        '-04:00||America/St_Lucia'=>'(-04:00) St_Lucia',
        '-04:00||America/St_Thomas'=>'(-04:00) St_Thomas',
        '-04:00||America/St_Vincent'=>'(-04:00) St_Vincent',
        '-04:00||America/Thunder_Bay'=>'(-04:00) Thunder_Bay',
        '-04:00||America/Toronto'=>'(-04:00) Toronto',
        '-04:00||America/Tortola'=>'(-04:00) Tortola',
        '-05:00||America/Atikokan'=>'(-05:00) Atikokan',
        '-05:00||America/Bogota'=>'(-05:00) Bogota',
        '-05:00||America/Cancun'=>'(-05:00) Cancun',
        '-05:00||America/Cayman'=>'(-05:00) Cayman',
        '-05:00||America/Chicago'=>'(-05:00) Chicago',
        '-05:00||America/Eirunepe'=>'(-05:00) Eirunepe',
        '-05:00||America/Guayaquil'=>'(-05:00) Guayaquil',
        '-05:00||America/Indiana/Knox'=>'(-05:00) Indiana/Knox',
        '-05:00||America/Indiana/Tell_City'=>'(-05:00) Indiana/Tell_City',
        '-05:00||America/Jamaica'=>'(-05:00) Jamaica',
        '-05:00||America/Lima'=>'(-05:00) Lima',
        '-05:00||America/Matamoros'=>'(-05:00) Matamoros',
        '-05:00||America/Menominee'=>'(-05:00) Menominee',
        '-05:00||America/North_Dakota/Beulah'=>'(-05:00) North_Dakota/Beulah',
        '-05:00||America/North_Dakota/Center'=>'(-05:00) North_Dakota/Center',
        '-05:00||America/North_Dakota/New_Salem'=>'(-05:00) North_Dakota/New_Salem',
        '-05:00||America/Panama'=>'(-05:00) Panama',
        '-05:00||America/Rainy_River'=>'(-05:00) Rainy_River',
        '-05:00||America/Rankin_Inlet'=>'(-05:00) Rankin_Inlet',
        '-05:00||America/Resolute'=>'(-05:00) Resolute',
        '-05:00||America/Rio_Branco'=>'(-05:00) Rio_Branco',
        '-05:00||America/Winnipeg'=>'(-05:00) Winnipeg',
        '-06:00||America/Bahia_Banderas'=>'(-06:00) Bahia_Banderas',
        '-06:00||America/Belize'=>'(-06:00) Belize',
        '-06:00||America/Boise'=>'(-06:00) Boise',
        '-06:00||America/Cambridge_Bay'=>'(-06:00) Cambridge_Bay',
        '-06:00||America/Costa_Rica'=>'(-06:00) Costa_Rica',
        '-06:00||America/Denver'=>'(-06:00) Denver',
        '-06:00||America/Edmonton'=>'(-06:00) Edmonton',
        '-06:00||America/El_Salvador'=>'(-06:00) El_Salvador',
        '-06:00||America/Guatemala'=>'(-06:00) Guatemala',
        '-06:00||America/Inuvik'=>'(-06:00) Inuvik',
        '-06:00||America/Managua'=>'(-06:00) Managua',
        '-06:00||America/Merida'=>'(-06:00) Merida',
        '-06:00||America/Mexico_City'=>'(-06:00) Mexico_City',
        '-06:00||America/Monterrey'=>'(-06:00) Monterrey',
        '-06:00||America/Ojinaga'=>'(-06:00) Ojinaga',
        '-06:00||America/Regina'=>'(-06:00) Regina',
        '-06:00||America/Swift_Current'=>'(-06:00) Swift_Current',
        '-06:00||America/Tegucigalpa'=>'(-06:00) Tegucigalpa',
        '-06:00||America/Yellowknife'=>'(-06:00) Yellowknife',
        '-07:00||America/Chihuahua'=>'(-07:00) Chihuahua',
        '-07:00||America/Creston'=>'(-07:00) Creston',
        '-07:00||America/Dawson'=>'(-07:00) Dawson',
        '-07:00||America/Dawson_Creek'=>'(-07:00) Dawson_Creek',
        '-07:00||America/Fort_Nelson'=>'(-07:00) Fort_Nelson',
        '-07:00||America/Hermosillo'=>'(-07:00) Hermosillo',
        '-07:00||America/Los_Angeles'=>'(-07:00) Los_Angeles',
        '-07:00||America/Mazatlan'=>'(-07:00) Mazatlan',
        '-07:00||America/Phoenix'=>'(-07:00) Phoenix',
        '-07:00||America/Tijuana'=>'(-07:00) Tijuana',
        '-07:00||America/Vancouver'=>'(-07:00) Vancouver',
        '-07:00||America/Whitehorse'=>'(-07:00) Whitehorse',
        '-08:00||America/Anchorage'=>'(-08:00) Anchorage',
        '-08:00||America/Juneau'=>'(-08:00) Juneau',
        '-08:00||America/Metlakatla'=>'(-08:00) Metlakatla',
        '-08:00||America/Nome'=>'(-08:00) Nome',
        '-08:00||America/Sitka'=>'(-08:00) Sitka',
        '-08:00||America/Yakutat'=>'(-08:00) Yakutat',
        '-09:00||America/Adak'=>'(-09:00) Adak'
    );

Eu o usei em muitos projetos, compartilhando para ajudá-lo. Obrigado por fazer esta pergunta.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.