27

2007 年,我们改用夏令时的日子发生了变化。任何在该更改之前的 DST 扩展范围内的日期都报告 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>
4

2 回答 2

35

使用当前 DST 规则实际上是指定的行为,并忽略在特定日期/时间被检查的那些。参见ES5 15.9.1.8

“ECMAScript 的实现不应该试图确定确切的时间是否受夏令时的影响,而只是如果当时使用了当前的夏令时算法,夏令时是否会生效。这避免了诸如此类的并发症考虑到该地区全年遵守夏令时的年份。”

规则是:将当前 DST 规则应用于指定的任何时间。这会导致毫无意义的行为,但这是 ECMAScript 所需要的。

有可能——甚至可能——这种行为将在未来版本的 ECMAScript 中发生变化,要求在所有时间点都使用实际的 DST 规则。这最初不是必需的,因为它给实施者带来了运输 tzdata 的负担。然而,这种语言已经变得足够重要,从长远来看,可能每个人都不得不接受它。但据我所知,这种变化可能还需要几年的时间,所以不要屏住呼吸。

于 2013-06-05T23:23:08.330 回答
4

我已经确认这是 JavaScript 中的一个真正的错误。

  • 使用遵循夏令时的常见美国时区进行测试
    • 东部、中部、山区、太平洋
  • 在 Chrome、Firefox、Safari 中测试并失败(最新版本)
  • 在 IE 6、7、8、9 中测试并失败。
  • 在 IE 10 中测试并通过(不受影响)。
  • 在 Windows 7、8 和 Mac OSX 上测试。

这很令人不安。有谁知道根本原因?

我认为这可能是 WebKit 错误,但 Firefox 使用 Gecko。

我检查了各种问题列表,但在任何地方都找不到这个特定问题。也许我错过了什么。我不确定在哪里提交错误报告,因为它会影响多个地方。

也许这是一个核心的 JavaScript 错误?我真的很难相信这个基本的东西被单元测试忽略了。

我认为这可能只是影响 Windows 系统,因为操作系统具有 Windows 时区而不是 TZDB,但情况似乎并非如此,因为它也发生在 Mac 上。

我们都知道 JavaScript 日期很麻烦,但我认为我们至少可以依靠这一点。您甚至不必查看偏移量或涉及解析。只需检查以下值:

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

2004 年在美国,夏令时于 10 月 31 日凌晨 2:00 结束,时钟回滚到凌晨 1:00。所以到 11 月 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)

它将过渡日期定在 11 月 7 日。这就是目前生效的“11 月的第一个星期日”规则,但在 2004 年,该规则应该是“10 月的最后一个星期日”的旧规则。

更新 1

它似乎不限于浏览器。 它在 Node.js 中也失败了

Node.js 截图

为了证明 IE 没问题,下面是 IE10 的输出:

IE10 截图

有趣的是,IE 和 Firefox 将 1:00 的歧义解析为夏令时,而 Chrome 将其解析为标准时间,但这是一个单独的问题。它确实选择了正确的过渡日期。

更新 2

值得一提的是,在最新的 Firefox 21 中,这个问题确实发生了,但它的表现有所不同,因为它与另一个为标准名称切换日光的问题混合在一起,即使使用了正确的偏移量。换句话说,在 Firefox 上,输出是这样的:

火狐截图

于 2013-06-05T19:58:28.513 回答