пятница, 28 ноября 2008 г.

Почему летнее время не интуитивно

Это перевод Why Daylight Savings Time is nonintuitive. Автор: Реймонд Чен.

Добро пожаловать читатели Knowledge Base article 932955! Помните, что информация на этом вэб-сайте не является официальной документацией Microsoft.

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

Люди часто жалуются на то, что все функции преобразования временной зоны типа FileTimeToLocalFileTime используют текущее DST-смещение (Daylight Saving Time - летнее время) вместо смещения, которое действовало в рассматриваемое время.

Например, предположим, что у вас есть структура FILETIME (TFileTime), которая представляет "1 января 2000, 12:00 AM". Если вы будете в Редмонде в летнее время, то структура будет сконвертирована в "31 декабря 1999, 5:00 PM" - с разницей в 7 часов, хотя разница во времени между Редмондом и UTC в Новый Год была 8 часов (т.е. когда люди в Лондоне праздновали Новый Год, в Редмонде было 4 PM, а не 5 PM).

Причина в том, что время переводится из "1 января 2000, 12:00 AM UTC" в "31 декабря, 1999 5:00 PM PDT" (т.е. переводит в тихоокеанское летнее время). Поэтому, технически, это преобразование корректно. Конечно же, никто не использовал PDT 31-го декабря 1999 в Редмонде; все использовали PST (тихоокеанское зимнее время).

Почему бы функциям перевода времени не использовать подходящее смещение в зависимости от времени года?

Одной причиной будет то, что тогда FileTimeToLocalFileTime и LocalFileTimeToFileTime не будут противоположностью друг другу. Если у вас будет местное время в пределах "пропавшего часа" во время перевода со стандартного на летнее время, то у него не будет соответствующего UTC-времени, потому что тогда не было 2:30 AM (часы перепрыгнули с 2 AM на 3 AM). Аналогично, местное время в 2:30 AM во время перехода обратно будет иметь два соответствующих UTC-времени.

Другая причина - постоянное изменение законов, регулирующих переход на летнее время. Например, если бы год в примере был бы не 2000, а 1997-й, то перевод был бы и интуитивно правильным, потому что Соединённые Штаты были на летнем времени весь год из-за энергетического кризиса. Конечно же, такая информация нигде не записывается в структуре TIME_ZONE_INFORMATION (TTimeZoneInformation). Похожим образом, во время Второй Мировой Соединённые Штаты использовали летнее время круглый год. А между 1945 и 1966 DST-правила менялись от региона к региону.

DST-правила меняются даже сегодня. Время перевода часов в Израиле устанавливается Кнессетом каждый год. В результате не существует единой формулы для каждого дня, нет возможности узнать её раньше времени.

(Предупреждение: дальше идёт материал о .NET; это уже второй день подряд, и что на меня нашло!?)

Сравните вывод FileInfo.LastWriteTime.ToString('f') с тем, что вы видите на вкладчке свойств файла, который последний раз изменялся не в той же зоне, что действует сейчас (т.е. если сейчас зимнее время, то посмотрите файл, созданный летом и наоборот). Например, пусть файл модифицировался последний раз 17-го Октября, когда ещё действовало летнее, но сейчас действует зимнее время. В свойствах файла в Проводнике вы увидите "Четверг, 17 октября 2003 г., 8:45:38 AM", но FileInfo из .NET сообщит о "Четверг, 17 октября 2003 г., 9:45 AM".

En gang til for prins Knud: Win32 не пытается угадывать, какие правила для времени действовали в указанное время. Поэтому Win32 говорит "Четверг, 17 октября 2003 г., 8:45:38 AM PST". Заметьте: Pacific Standard Time (зимнее время). Даже хотя 17-го октября действовало летнее время, Win32 отображает его как зимнее, потому что именно это то время, что действует сейчас.

.NET говорит: "ну, если правила, действующие сейчас, действовали бы и 17 октября 2003-го, то тогда это было бы летнее время", поэтому .NET показывает: "Четверг, 17 октября 2003 г., 9:45 AM PDT" - летнее время.

Итак, .NET даёт значение, которое более правильно интуитивно, но также может быть потенциально неверным, и, кроме того, не всегда обратимым. Win32 даёт интуитивно неверное значение, которое, тем не менее, является строго точным.

Я подозреваю, что такое поведение в .NET введено для совместимости с Visual Basic, но тут я точно не уверен.

2 комментария:

  1. Как обычно, больше всех повезло Vista и выше - в ней есть новые функции GetDynamicTimeZoneInformation и GetTimeZoneInformationForYear, которые позволяют учитывать историю изменения в правилах перехода на летнее время в каждом году.

    Понятно, что даже это не панацея во всех случаях.

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.