2

简洁版本

在 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)构造一个Date时间值为 UTC(yyyy-mm-dd hh:mi:ss)的 a,其中

UTC( t ) = t – LocalTZA – DaylightSavingTA( t – LocalTZA)

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

但是,我不清楚 DaylightSavingTA在太平洋时区或 t = 2013-10-20 03:34:56 在太平洋时区参数应该返回什么.

4

2 回答 2

3

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

好问题!你是正确的,这取决于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() 函数中调用相同的函数,使用t该函数中的一个表示 DST 调整时间的函数。因此,在 DST 开始时不存在的本地小时内,DaylightSavingTA(the-dst-adjusted-time-which-is-one-hour-ahead) 为 1 小时。最后:

new Date(2013, 9, 20) 可以合法地返回 10 月 19 日吗?

是的。

我问是因为我(可能还有其他人)已经编写了类似 new Date(year, month, day) 的代码来构造一个没有时间的日期,显然这并不总是有效!

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

于 2013-09-19T15:34:24.013 回答
1

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

要点是 ECMAScript 5在第 15.9.1.8 节中定义了 DaylightSavingTA 算法的一部分,但它确实做得很糟糕ECMAScript 6 的情况正在好转。

关于为无效输入向前或向后跳过,规范不要求它以任何一种方式下降。但实际上,除了规范之外,只有执行以下操作之一才有意义:

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

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

我想不出任何像 Chrome 一样向后移动有意义的实际用例。它在 ES5 规范中是有效的,但它没有任何意义。

Firefox 只是有一个错误,它的标签被弄乱了,这里也有描述

还要记住,虽然大多数区域的夏令时过渡一小时,但至少有一个只有 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),它没有在弹簧前移过渡范围内定义,并且在后退过渡范围内根本不是一个函数。

于 2013-09-20T00:35:45.457 回答