夏令时开始时间无效

简洁版本

在JavaScript中, new Date(2013, 9, 20)合法返回10月19日吗?

长版本

夏令时开始时,由于时钟向前调整,因此当地时间有差距。 如果我构造的Date对象的时间落在这个间隙内,根据ECMAScript规范,预期的行为是什么?

各种浏览器的行为有所不同,如下所示。 (我在Windows 8上运行这些测试。)

示例1:在太平洋时区(UTC-08)中,表达式

new Date(2013, 2, 10, 2, 34, 56).toString() // Sun Mar 10 2013 02:34:56

给出以下结果:

IE 10:      Sun Mar 10 03:34:56 PDT 2013
IE 11:      Sun Mar 10 2013 03:34:56 GMT-0700 (Pacific Daylight Time)
Chrome 29:  Sun Mar 10 2013 01:34:56 GMT-0800 (Pacific Standard Time)
Firefox 23: Sun Mar 10 2013 03:34:56 GMT-0700 (Pacific Standard Time)

例2:在巴西利亚时区(UTC-03)表达

new Date(2013, 9, 20, 0, 34, 56).toString() // Sun Oct 20 2013 00:34:56

给出以下结果:

IE 10:      Sun Oct 20 01:34:56 UTC-0200 2013
IE 11:      Sun Oct 20 2013 01:34:56 GMT-0200 (E. South America Daylight Time)
Chrome 29:  Sat Oct 19 2013 23:34:56 GMT-0300 (E. South America Standard Time)
Firefox 23: Sat Oct 19 2013 23:34:56 GMT-0300

基于这两个例子,IE似乎在向前调整时间,Chrome向后调整时间,Firefox无法下定决心。

规范说:根据我可以收集的内容, new Date(yyyy, mm-1, dd, hh, mi, ss)以时间值UTC(yyyy-mm-dd hh:mi:ss)构造Date 。 ,在哪里

UTC(t)= t - LocalTZA - DaylightSavingTA(t - LocalTZA)

LocalTZA是标准时间的本地时区调整(例如,太平洋时区的-08:00),而DaylightSavingTA(t)是t的夏令时调整(例如,在DST期间01:00,否则00:00 )。

但我不清楚,DaylightSavingTA应该在太平洋时区t = 2013-03-10 10:34:56或巴西利亚时区的t = 2013-10-20 03:34:56返回一个参数。


根据ECMAScript规范,预期的行为是什么?

好问题! 您确定这取决于严格未定义的DaylightSavingTA ,但是我们可以从反向函数中使用DaylightSavingTA的方式推导出有关DaylightSavingTA含义:

LocalTime(t)= t + LocalTZA + DaylightSavingTA(t)

为了将UTC t正确转换为本地时间,DaylightSavingTA(hour_at_beginning_of_dst)必须为1小时,而DaylightSavingTA(hour_after_end_of_dst)必须为0。

在UTC()函数中使用在该函数中表示DST调整的时间的t来调用相同的函数。 因此,在夏令时开始时不存在的当地小时,DaylightSavingTA(每小时提前调整时间)为1小时。 所以:

新日期(2013,9,20)可以合法返回10月19日吗?

是。

我在问,因为我(可能还有其他人)已经编写了像新日期(年,月,日)这样的代码来构建一个没有时间的日期,而且显然这并不总是奏效!

确实! 使用UTC日期进行这种计算 - new Date(Date.UTC(2013, 9, 20))getUTC*方法。 一般来说,除了最终的面向用户的时间表示外,最好坚持使用UTC。


你的观察是正确的,我也做了类似的观察。 阅读这篇文章和我写的博客文章以获取更多详细信息。

要点是ECMAScript 5在15.9.1.8节中定义了DaylightSavingTA算法的一部分,但它确实做了一件非常糟糕的工作。 对于ECMAScript 6,情况看起来更好。

关于向前或向后跳过无效输入,规范并不要求它以任何方式。 尽管如此,除了实际情况外,只有做到以下几点才有意义:

  • 向前跳过DST金额。 这很有意义,因为如果有人忘记调整输入中的DST,您可能会遇到无效值。

  • 抛出错误或异常,因为该日历时间不存在。 JavaScript不这样做,但其他语言/库可以。 例如,如果传递一个无效的本地时间,.NET的TimeZoneInfo.ConvertTimeToUtc方法将引发异常。

  • 我想不出有什么真实世界的用例,它像Chrome一样向后移动是有意义的。 这是有效的ES5规范,但它没有任何意义。

    Firefox只有一个标签混乱的bug,这里也有描述。

    另外请记住,虽然大多数地区的DST过渡了一个小时,但至少有一个地区只有30分钟( Australia/Lord_Howe ),而一些南极地区甚至更加陌生。

    另一个相关的问题是在回退转换中含糊不清。 由于DST,有效的本地时间可能代表两个不同的UTC时刻。 同样,ES5规范也没有提到在这种情况下会发生什么。 实际上,我们再次发现每个浏览器的行为不同。 有些人需要白天,因为这是两个可能时刻中的第一个。 其他人则需要标准时间,因为这是“标准”。

    在其他框架中,Python(通过pytz)将抛出一个异常,而.NET的TimeZoneInfo方法将假定“标准”时间。 像Noda Time这样的图书馆可以为您提供选择。 但在JavaScript中,行为是特定于实现的。

    对于模糊的时间或无效的时间,你可以做的最好的事情是测试你的输入。 如果无效,请提示用户输入有效时间。 如果不明确,请提示用户选择两种可能性中的一种。

    考虑LocalTime(t)函数的图表,因为它适用于美国太平洋时间( America/Los_Angeles )。

    春季前进DST转换

    倒退DST转换

    这是一个有效的函数,但是如果翻转X轴和Y轴,那么您将看到UTC(t)的效果,该效应没有在弹簧向前转换范围内定义,并且在下降的时候并不是一个函数,后退转换范围。

    链接地址: http://www.djcxy.com/p/29393.html

    上一篇: Invalid times at the start of Daylight Saving Time

    下一篇: Issues to get end DayLight Saving time