Xpoint
   [напомнить пароль]

Как определить время в разных городах, учитывая часовой пояс и летнее время?

Метки: [без меток]
2006-05-25 04:26:28 [обр] Алексей В. Иванов(25/2861)[досье]

Есть задача:
Нарисовать на сайте часы на Flash, которые показывают время в нескольких городах. Более конкретно: Токио, Нью-Йорк, Москва и Лондон.

Казалось бы, взять UTC и прибавить к нему смещение, но есть проблема — летнее время. У разных стран оно разное и переход происходит не в определённый день, а с субботы на воскресенье некого месяца, более того, попадаются сюрпризы вида:

On Monday August 8, 2005 President Bush signed into law a broad energy bill that will extend Daylight Saving Time by four weeks beginning in 2007.

Что лишает надежды написать что-то универсальное.
Может, кто знает, как красиво решается эта проблема? XML-сервисы какие или таблички "смещений" на 10 лет вперед есть? :)

спустя 4 часа 11 минут [обр] Дионис Сантин aka Человек с Ломом(15/406)[досье]

Буш все-таки непредсказуем, поверьте ;)
А вообще-то стоит посмотреть на всемирные сайты типа http://www.timeanddate.com/

+ NTP-сервера первого стратума: http://ntp.isc.org/bin/view/Servers/StratumOneTimeServers

спустя 16 минут [обр] Дмитрий Кучкин(6/236)[досье]
спустя 12 минут [обр] Дмитрий Кучкин(6/236)[досье]
Нужная информация в архиве ftp://elsie.nci.nih.gov/pub/tzdata2006g.tar.gz
Это исходники для *nix систем.
То же самое есть в каталоге /usr/src/share/zoneinfo BSD-систем, если были развернуты исходники.
спустя 59 минут [обр] Алексей В. Иванов(25/2861)[досье]
Спасибо. Чуть позже буду разбираться в ссылках.
Последний архив закачал, посмотрел что в нём... оказалась целая гуча геморроя. Но информация в любом случае очень полезная :)
Отрывок:
# Rule   NAME   FROM   TO   TYPE   IN   ON   AT   SAVE   LETTER/S
Rule   US   1918   1919   -   Mar   lastSun   2:00   1:00   D
Rule   US   1918   1919   -   Oct   lastSun   2:00   0   S
Rule   US   1942   only   -   Feb   9   2:00   1:00   W # War
Rule   US   1945   only   -   Aug   14   23:00u   1:00   P # Peace
Rule   US   1945   only   -   Sep   30   2:00   0   S
Rule   US   1967   2006   -   Oct   lastSun   2:00   0   S
Rule   US   1967   1973   -   Apr   lastSun   2:00   1:00   D
Rule   US   1974   only   -   Jan   6   2:00   1:00   D
Rule   US   1975   only   -   Feb   23   2:00   1:00   D
Rule   US   1976   1986   -   Apr   lastSun   2:00   1:00   D
Rule   US   1987   2006   -   Apr   Sun>=1   2:00   1:00   D
Rule   US   2007   max   -   Mar   Sun>=8   2:00   1:00   D
Rule   US   2007   max   -   Nov   Sun>=1   2:00   0   S
спустя 4 часа 29 минут [обр] Давид Мзареулян(14/1003)[досье]

Вообще, врукопашную это делать — сильно себя не любить. Обычно код для работы с таймзонами выглядит так (цитирую одну php-программу):

function ZoneTime($zone, $timestamp=0) {
    if($timestamp==0) $timestamp=time();
    $env_tz = (string)getenv("TZ");
    putenv("TZ=".$zone);
    $ltime = localtime($timestamp, true);
    putenv("TZ=".$env_tz);
    return $ltime;
}

Выглядит всё это, мягко говоря, диковато, но это и вправду самый простой и надёжный способ решить задачу. Вся ответственность перекладывается на ОС.

спустя 7 минут [обр] Давид Мзареулян(14/1003)[досье]
Возможно, во флэше есть какие-то свои механизмы для этого?
спустя 1 час 35 минут [обр] Алексей В. Иванов(25/2861)[досье]

Не, на флэше максимум, что можно узнать, это клиентскую информацию о времени (ну и UTC). Так, чтобы город указывать, увы, нет :)

По поводу функции ZoneTime...
Я так понимаю, что в неё надо строку $zone заправлять, но проблема в том, что для летнего времени и зимнего это строка разная, например, если London, то нужно заправлять либо "GMT", либо "BST". Для New York'а "EDT" или "EST" и т.д.
Так что пользы он неё в таком виде нет :(

спустя 12 минут [обр] Давид Мзареулян(14/1003)[досье]
Алексей В. Иванов[досье] Нет, туда запихивается зона вида “Europe/London” или “America/New_York”. См. http://www.php.net/manual/en/timezones.php.
спустя 1 минуту [обр] Давид Мзареулян(14/1003)[досье]

Вот, к примеру, выдержка из PEAR-овского модуля Date:

   'America/New_York' => array(
        'offset' => -18000000,
        'longname' => 'Eastern Standard Time',
        'shortname' => 'EST',
        'hasdst' => true,
        'dstlongname' => 'Eastern Daylight Time',
        'dstshortname' => 'EDT' ),

Так что всё уже придумано до нас.

спустя 21 минуту [обр] Алексей В. Иванов(25/2861)[досье]
Я несказанно рад, спасибо, Давид[досье]. Отменно работает!
Ухожу сушить штаны.
спустя 11 часов [обр] Алексей В. Иванов(25/2861)[досье]
Сижу и думаю... почему на сайт PEAR не залез сразу, как я обычно это делаю?!
Кроссплатформенный вариант выглядит очень просто и красиво:
require "Date/TimeZone.php";
require "Date.php";

$zones = array('America/New_York', 'Europe/London', 'Europe/Moscow', 'Asia/Tokyo');
foreach ($zones as $zone) {
   $z = new Date_TimeZone($zone);
   print "$zone offset: " . $z->getOffset(new Date())/3600000 . "\n";
}
спустя 1 час 14 минут [обр] Rom McRitsky(34/441)[досье]
IMHO, стоит в FAQ / БЗ
спустя 9 часов [обр] Сергей Пантелеев(0/15)[досье]
Буквально на днях решал схожую проблему на Perl. Спас CPANовский модуль DateTime::TimeZone, позволяющий переводить время между таймзонами, локальным временем, UTC. Ну и смещение между часовыми поясами тоже узнать можно конечно. Пример работы с модулем:
use DateTime;
use DateTime::TimeZone;

my $tz = DateTime::TimeZone->new( name => 'America/Chicago' );

my $dt = DateTime->now();
my $offset = $tz->offset_for_datetime($dt);
$dt->set_time_zone('Europe/Moscow');
спустя 5 часов [обр] Сергей Чернышев(27/589)[досье]

Вот хороший ресурс: http://datetime.perl.org/ и http://datetime.perl.org/?Modules в дополнение к нему.

Для тех кто еще не сталкивался - имейте ввиду, что многие TimeZones не стандартны и вам может сильно пригодиться DateTime::TimeZone::Alias и соответствующий ресурс: http://www.worldtimezone.com/wtz-names/timezonenames.html

Powered by POEM™ Engine Copyright © 2002-2005