Часовой пояс JavaScript неверен для правил перехода на летнее время

В 2007 году изменились дни перехода на летнее время. Любая дата, которая подпадает под расширенный диапазон DST до этого изменения, сообщает о некорректном смещении часового пояса в Chrome и Firefox. Это как Firefox и Chrome не обращают внимания на то, что у DST были разные дни.

Если вы запустите следующий script, он сообщит о смещении в 240 минут. Это неверно, он должен сообщить 300 минут. IE10 делает это правильно. Кто-нибудь знает об исправлении?

alert(new Date('11/04/2004').getTimezoneOffset());

UPDATE:

Вот интересный фрагмент кода, который я только что взломал (см. ниже). Это действительно удивительно, как далеко от большинства дат в каждом браузере, но IE. Сравните даты начала и окончания с этим: http://www.timeanddate.com/worldclock/timezone.html?n=77&syear=2000

В итоге я просто заменил прототип Date для getTimezoneOffset моим собственным, который вычисляет его на основе жестко закодированной таблицы. Это работает для нас, потому что мы занимаемся только бизнесом в США. Это о худшем возможном решении, которое я могу себе представить, хотя...

<!DOCTYPE html>
<html>
    <head>
        <title>Moment Test</title>
        <script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.0.0/moment.min.js"></script>
        <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
        <script>
var lastOffset = null;
var $tbody = null;
var endDate = new Date('01/01/2021');

function addDate(d) {
    if($tbody === null)
        $tbody = $('#dates');

    var offset = d.getTimezoneOffset();
    var s = '';
    if(lastOffset != offset) {
        if(lastOffset != null)
            s = '<tr style="background-color: red;">';
        lastOffset = offset;
    }
    else {
        s = '<tr>';
    }
    var m = new moment(d);
    s += '<td>' + m.format('YYYY-MM-DD') + '</td><td>' + m.format('YYYY-MM-DDTHH:mm:ssZ') + '</td><td>' + m.format('YYYY-MM-DDTHH:mm:ss') + '</td><td>' + offset + '</td></tr>';
    $tbody.append($(s));
    d.setDate(d.getDate() + 1);

    if(d < endDate)
        window.setTimeout(function(){addDate(d)}, 0);
}

        </script>
    </head>
    <body>
        <button onclick="addDate(new Date('01/01/1980'));">Fill Table</button>
        <table border="1">
            <thead><tr><th>Date</th><th>Date 2</th><th>Date 3</th><th>TZ Offset</th></tr></thead>
            <tbody id='dates'></tbody>
        </table>
    </body>
</html>

Ответ 1

Фактически задано поведение для использования текущих правил летнего времени и игнорировать те, которые находятся на месте в конкретную дату/время. См. ES5 15.9.1.8:

"Реализация ECMAScript не должна пытаться определить, было ли точное время подвержено летнему времени, но только, было ли использование летнего времени действенным, если бы в то время использовался алгоритм текущего летнего времени. избегает осложнений, таких как учет лет, в которых местность наблюдала летнее время года".

Правила: применяют текущие правила DST к тому времени, которое было указано. Это приводит к ненормальному поведению, но это то, что требует ECMAScript.

Возможно, возможно, даже, что это поведение изменится в будущей версии ECMAScript, чтобы требовать фактических правил DST во всех точках времени. Первоначально это не требовалось из-за бремени доставки tzdata, которое оно налагает на исполнителей. Однако язык приобрел достаточно важное значение, однако, вероятно, всем придется просто втянуть его в конечном итоге. Но изменение может занять много лет для всего, что я знаю, поэтому не задерживайте дыхание.

Ответ 2

Я подтвердил, что это настоящая ошибка в JavaScript.

  • Протестировано с использованием обычных часовых поясов США, которые следуют за летним временем
    • Восточная, Центральная, Гора, Тихий океан
  • Протестировано в Chrome, Firefox, Safari и не удалось (последние версии)
  • Протестировано в IE 6, 7, 8, 9 и не удалось.
  • Протестировано в IE 10 и прошло (не затронуто).
  • Протестировано в Windows 7, 8 и Mac OSX.

Это довольно тревожно. Кто-нибудь знает основную причину?

Я думал, что это может быть ошибка WebKit, но Firefox использует Gecko.

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

Возможно, это основная ошибка JavaScript? Мне действительно трудно поверить, что что-то из этого элемента было упущено с помощью unit test.

Я подумал, что, возможно, это просто повлияло на системы Windows из-за того, что ОС имеет временные зоны Windows вместо TZDB, но это не похоже на то, что происходит на Mac.

Мы все знаем, что даты в формате JavaScript являются отвратительными, но я думал, что мы можем хотя бы зависеть от этого. Вам даже не нужно смотреть на смещение или включать парсинг. Просто проверьте значение:

new Date(2004,10,4)  // recall, js months are 0-11, so this is Nov. 4 2004.

В 2004 году в Соединенных Штатах летнее время закончилось 31 октября в 2 часа ночи, когда часы вернулись к 1:00 утра. Таким образом, к 4 ноября, они, безусловно, должны быть в стандартное время, но это не так! Например, в инструментах Chrome dev на консоли, с часами, установленными в восточном часовом поясе США:

> new Date(2004,10,7,0,0)
  Sun Nov 07 2004 00:00:00 GMT-0400 (Eastern Daylight Time)

> new Date(2004,10,7,1,0)
  Sun Nov 07 2004 01:00:00 GMT-0500 (Eastern Standard Time)

Он помещает дату перехода 7 ноября. Это следующее правило "Первое воскресенье ноября", которое действует в настоящее время, но в 2004 году это правило должно было быть старым в "Последнее воскресенье октября".

ОБНОВЛЕНИЕ 1

Он не ограничен браузером. Он также терпит неудачу в Node.js

Node.js Screenshot

И просто, чтобы доказать, что IE в порядке, вот вывод из IE10:

IE10 Screenshot

Интересно, что IE и Firefox разрешают неопределенность 1:00 как Daylight Time, в то время как Chrome разрешает это как стандартное время, но это отдельная проблема. Он выбирает правильную дату перехода.

ОБНОВЛЕНИЕ 2

Стоит упомянуть, что в последнем Firefox 21 эта проблема возникает, но она выглядит по-другому, поскольку она усугубляется еще одной проблемой, которая переключает дневной свет для стандартных имен, даже если используется правильное смещение. В других словах, в Firefox, вывод выглядит следующим образом:

Firefox Screenshot