JavaScript Time Zone is wrong for past Daylight Saving Time transition rules
2007年,我们改用夏令时的日子发生了变化。在此更改之前属于DST扩展范围内的任何日期都会在Chrome和Firefox中报告错误的时区偏移。这就像Firefox和Chrome没有注意到DST曾经有过不同日子的事实。
如果您运行以下脚本,它将报告240分钟的偏移量。这是不正确的,它应该报告300分钟。 IE10正确地做到了这一点。有谁知道修复?
1 | alert(new Date('11/04/2004').getTimezoneOffset()); |
更新:
这是我刚刚攻击的一段有趣的代码(见下文)。令人惊讶的是,除了IE,每个浏览器的大多数日期都有多远。将开始日期和结束日期与此进行比较:http://www.timeanddate.com/worldclock/timezone.html?n = 77& syear = 2000
我最后用我自己的getTimezoneOffset替换了Date的原型,它根据硬编码表计算它。这对我们有用,因为我们只在美国做生意。这是我能想象到的最糟糕的解决方案......
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <!DOCTYPE html> <html> <head> Moment Test <script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.0.0/moment.min.js"> <script src="http://code.jquery.com/jquery-1.10.1.min.js"> 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); } </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> |
它实际上是指定使用当前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系统,因为操作系统有Windows时区而不是TZDB,但事实并非如此,因为它也发生在Mac上。
我们都知道JavaScript日期很棘手,但我认为我们至少可以依赖于此。您甚至不必查看偏移量或涉及解析。只需检查以下值:
1 | new Date(2004,10,4) // recall, js months are 0-11, so this is Nov. 4 2004. |
2004年在美国,夏令时于10月31日凌晨2点结束,当时钟回到凌晨1点。所以到11月4日,他们肯定都应该在标准时间,但他们不是!例如,在控制台上的Chrome开发工具中,时钟设置为美国东部时区:
1 2 3 4 5 | > 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日。这就是现在生效的"十一月的第一个星期日"规则,但在2004年,该规则应该是"十月的最后一个星期日"的旧规则。
更新1
它似乎不限于浏览器。它在Node.js中也失败了
只是为了证明IE很好,这是IE10的输出:
有趣的是,IE和Firefox将1:00的歧义解析为日光时间,而Chrome将其解析为标准时间,但这是一个单独的问题。它确实选择了正确的过渡日期。
更新2
值得一提的是,在最新的Firefox 21中,这个问题确实发生了,但它本身就有所不同,因为它更复杂的是另一个问题,它为标准名称切换日光,即使使用了正确的偏移量。换句话说,在Firefox上,输出如下: