简体   繁体   English

过去的夏令时过渡规则,JavaScript时区错误

[英]JavaScript Time Zone is wrong for past Daylight Saving Time transition rules

In 2007, the days that we switch to daylight savings time changed. 在2007年,我们改用夏时制的日子发生了变化。 Any date that falls within the extend range of DST prior to that change is reporting an incorrect timezone offset in Chrome and Firefox. 在此更改之前,属于DST扩展范围的任何日期都将报告Chrome和Firefox中不正确的时区偏移。 It's like Firefox and Chrome don't pay attention to the fact that DST used to have different days. 就像Firefox和Chrome不用注意DST过去的日子不同。

If you run the following script it will report an offset of 240 minutes. 如果运行以下脚本,它将报告偏移量为240分钟。 That's incorrect, it should report 300 minutes. 这是不正确的,它应该报告300分钟。 IE10 does this correctly. IE10可以正确执行此操作。 Does anyone know of a fix? 有人知道解决办法吗?

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

UPDATE: 更新:

Here's an interesting piece of code I just hacked together (see below). 这是我刚刚一起学习的一段有趣的代码(请参见下文)。 It's really surprising how far off most of the dates are in every browser but IE. 令人惊讶的是,除了IE之外,每种日期在大多数浏览器中的距离还有多远。 Compare the begin and end dates to this: http://www.timeanddate.com/worldclock/timezone.html?n=77&syear=2000 比较开始日期和结束日期与此: http : //www.timeanddate.com/worldclock/timezone.html?n=77&syear=2000

I ended up just replacing Date's prototype for getTimezoneOffset with my own that calculates it based on a hard-coded table. 我最终只是用我自己的Date原型将getTimezoneOffset替换为Date的原型,该原型根据硬编码表进行计算。 That works for us because we only do business in the US It's about the worst possible solution I can imagine though... 这对我们有用,因为我们仅在美国开展业务,但这是我能想到的最糟糕的解决方案...

<!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>

It's actually specified behavior to use the current DST rules, and to ignore the ones in place at the particular date/time being examined. 实际上是指定行为,以使用当前的DST规则,而忽略在检查的特定日期/时间到位的规则。 See ES5 15.9.1.8 : 参见ES5 15.9.1.8

"The implementation of ECMAScript should not try to determine whether the exact time was subject to daylight saving time, but just whether daylight saving time would have been in effect if the current daylight saving time algorithm had been used at the time. This avoids complications such as taking into account the years that the locale observed daylight saving time year round." “ ECMAScript的实现不应尝试确定确切的时间是否受夏时制的约束,而应确定如果当时使用了当前的夏时制算法,则夏时制是否会生效。这避免了诸如此类的复杂性。考虑到该语言环境全年观察夏令时的情况。”

The rules are: apply the current DST rules, to whatever time was specified. 规则是:将当前DST规则应用于指定的任何时间。 This results in arrant nonsense behavior, but it's what ECMAScript requires. 这会导致胡言乱语,但这正是ECMAScript所要求的。

It's possible -- likely, even -- that this behavior will change in a future version of ECMAScript, to require actual DST rules at all points in time be used. 在将来的ECMAScript版本中,这种行为甚至可能会改变,要求在所有时间点都使用实际的DST规则。 This wasn't required initially because of the burden of shipping tzdata that it imposes on implementers. 最初并不需要这样做,因为它会给实现者带来发送tzdata的负担。 The language has become important enough, however, that probably everyone will just have to suck it up in the long run. 语言已经变得足够重要,但是从长远来看,也许每个人都必须掌握它。 But the change could be years away for all I know, so don't hold your breath on it. 但是就我所知,这种变化可能还需要数年,所以不要屏住呼吸。

I have confirmed that this is a true bug in JavaScript. 我已经确认这是JavaScript中的错误。

  • Tested with common US time zones that follow daylight saving time 在遵循夏时制的美国常见时区进行测试
    • Eastern, Central, Mountain, Pacific 东部,中部,山脉,太平洋
  • Tested in Chrome, Firefox, Safari and failed (latest versions) 已在Chrome,Firefox,Safari中测试,并且失败(最新版本)
  • Tested in IE 6, 7, 8, 9 and failed. 在IE 6、7、8、9中进行了测试,但失败了。
  • Tested in IE 10 and passed (not affected). 在IE 10中测试并通过(不受影响)。
  • Tested on Windows 7, 8 and Mac OSX. 在Windows 7、8和Mac OSX上进行了测试。

This is pretty troubling. 这很麻烦。 Does anyone know the root cause? 有人知道根本原因吗?

I thought it might be a WebKit bug, but Firefox uses Gecko. 我以为可能是WebKit错误,但是Firefox使用Gecko。

I checked various issue lists and couldn't find this particular problem anywhere. 我检查了各种问题列表,在任何地方都找不到此特定问题。 Perhaps I missed something. 也许我错过了一些东西。 I'm not sure where to file a bug report, since it affects multiple places. 我不确定在哪里提交错误报告,因为它会影响多个地方。

Perhaps it is a core JavaScript bug? 也许这是JavaScript的核心错误? I really find it hard to believe that something this basic has been overlooked by a unit test. 我真的很难相信这个基本的东西已经被单元测试所忽略了。

I thought perhaps it was just affecting Windows systems, due to the OS having Windows timezones instead of TZDB, but that doesn't appear to be the case since it happens on Mac as well. 我认为这可能只是影响Windows系统,因为该操作系统具有Windows时区而不是TZDB,但是事实并非如此,因为它也发生在Mac上。

We all know JavaScript dates are screwy, but I thought we could at least depend on this. 我们都知道JavaScript日期是很麻烦的,但是我认为我们至少可以依靠它。 You don't even have to look at the offset, or involve parsing. 您甚至不必查看偏移量,也不必进行解析。 Just check the value of: 只需检查以下值:

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

In 2004 in the United States, daylight saving time ended on October 31 at at 2:00 AM, when the clocks rolled back to 1:00 AM. 在2004年的美国,夏令时于10月31日的凌晨2:00结束,而时钟又回到了凌晨1:00。 So by Nov 4th, they should certainly all be on standard time, but they're not! 因此,到11月4日,他们肯定都应该在标准时间上,但事实并非如此! For example, in Chrome dev tools on the console, with clock set to US Eastern time zone: 例如,在控制台上的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)

It's putting the transition date on Nov 7th. 过渡日期定在11月7日。 That's the following the "First Sunday in November" rule that is presently in effect, but in 2004 the rule should have been the old one of "Last Sunday in October". 这是继目前生效的“ 11月的第一个星期日”规则之后的,但是在2004年,该规则应该是“ 10月的最后一个星期日”的旧规则。

UPDATE 1 更新1

It does not appear limited to the browser. 它似乎不限于浏览器。 It also fails in Node.js 它还在Node.js中失败

Node.js截图

And just to prove that IE is fine, here is the output from IE10: 只是为了证明IE很好,这是IE10的输出:

IE10截图

Interesting that IE and Firefox resolve the 1:00 ambiguity as Daylight Time while Chrome resolves it as Standard Time, but that is a separate issue. 有趣的是,IE和Firefox将1:00歧义解决为“夏令时”,而Chrome将其解决为标准时间,但这是一个单独的问题。 It does pick the correct transition date. 它确实选择了正确的过渡日期。

UPDATE 2 更新2

It's worth mentioning that in the latest Firefox 21, this issue does happen, but it presents itself differently because it's compounded by another issue that switches daylight for standard names, even though the correct offset is used. 值得一提的是,在最新的Firefox 21中,确实发生了此问题,但其呈现方式却有所不同,因为即使使用了正确的偏移量, 另一个问题却又切换了标准名称的白天设置。 In otherwords, on Firefox, the output is like this: 换句话说,在Firefox上,输出如下:

Firefox屏幕截图

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM