【问题标题】:Invalid times at the start of Daylight Saving Time夏令时开始时的无效时间
【发布时间】:2013-09-24 17:07:44
【问题描述】:

短版

在 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 在巴西利亚时区。

【问题讨论】:

  • 好问题。最佳建议:不要这样做:)
  • @mplungjan:我问这个问题是因为我(可能还有其他人)已经编写了类似new Date(year, month, day) 的代码来构造一个没有时间的日期,显然这并不总是有效!
  • 我总是正常化。 new Date(year,month-1,date,0,0,0,0) 但你可以决定使用 new Date(year,month-1,date,12,0,0,0) 来确保 -X 不会让你昨天约会
  • @mplungjan:添加这些零没有帮助。将小时设置为 12 确实可以,但有多少开发人员会考虑这样做?

标签: javascript date time dst


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    你的观察是正确的,我也做过类似的。阅读this post 和the blog article I wrote 了解更多详情。

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

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

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

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

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

    Firefox 只是有一个错误,它的标签被弄乱了,即also described here。

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

    另一个相关的问题是回退过渡中的模糊性。由于 DST,存在重叠,有效的本地时间可能代表两个不同的 UTC 时刻。同样,ES5 规范对在这种情况下应该发生什么保持沉默。实际上,我们再次发现每个浏览器的行为都不同。有些人选择白天时间,因为这是两个可能的时刻中的第一个。其他人则采用标准时间,因为这是“标准”。

    在其他框架中,Python(通过 pytz)会抛出异常,而 .NET 的 TimeZoneInfo 方法将采用“标准”时间。 Noda Time 之类的库为您提供选择。但在 JavaScript 中,行为是特定于实现的。

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

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

               

               

    这是一个有效的函数,但是如果你翻转 X 轴和 Y 轴,你会看到 UTC(t) 的效果,它没有定义在弹簧向前的过渡范围内,并且根本不是一个函数后备过渡范围。

    【讨论】:

    • 感谢您的链接。您写道“规范不要求它以任何一种方式下降”,但是您如何看待 bobince 的结论,基于 LocalTime(t) 的公式,ECMAScript 5 规范实际上需要它要倒退吗?
    • Require 有点强...这是我发现与规范中的语言一致的唯一结果,但其中有一些基本假设,例如 DaylightSavingTA 是一个纯函数,它是理智所必需的,但没有明确说明。
    猜你喜欢
    • 2015-05-03
    • 2017-07-11
    • 2011-10-22
    • 1970-01-01
    • 2019-04-08
    • 2012-04-07
    • 2019-04-10
    • 2016-02-06
    • 2017-11-20
    相关资源
    最近更新 更多