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

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

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

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

ОБНОВИТЬ:

Вот интересный фрагмент кода, который я только что взломал (см. Ниже). Это действительно удивительно, как далеко большинство дат в каждом браузере, кроме 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>

2 ответа

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

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

> 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

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

IE10 Скриншот

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

ОБНОВЛЕНИЕ 2

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

Скриншот Firefox

Другие вопросы по тегам