短版
在JavaScript中, new Date(2013, 9, 20)
合法地返回10月19日?
长版
当夏令时开始时,随着时钟向前调整,当地时间存在间隙 . If I construct a Date object with a time that falls within this gap, what is the expected behavior according to the ECMAScript specification?
各种浏览器的行为不同,如下所示 . (我在Windows 8上运行了这些测试 . )
Example 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)
Example 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无法下定决心 .
What the specification says: 根据我可以收集到的信息, 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 .
2 回答
好问题!你是正确的,这取决于严格未定义的
DaylightSavingTA
,但是我们可以从它在反函数中使用时的工作方式得出DaylightSavingTA
的含义:为此,将UTC t正确转换为本地时间,DaylightSavingTA(hour_at_beginning_of_dst)必须为1小时,DaylightSavingTA(hour_after_end_of_dst)必须为0 .
使用
t
在UTC()函数中调用相同的函数,该函数表示DST调整的时间 . 因此,在DST开始时不存在的当地时间,DaylightSavingTA(-dst-adjusted-time-is-one-hour-ahead-ahead)是1小时 . 所以:是 .
确实!将UTC日期用于此类计算
new Date(Date.UTC(2013, 9, 20))
和getUTC*
方法 . 一般来说,除了最终面向用户的时间呈现之外,最好坚持使用UTC .你的观察是正确的,我已经做了类似的观察 . 有关其他详细信息,请阅读this post和the blog article I wrote .
要点是ECMAScript 5在第15.9.1.8节中定义了DaylightSavingTA算法的一部分,但它确实很糟糕 . ECMAScript 6的效果看起来更好 .
关于向前或向后跳过无效输入,规范不要求它以任何方式掉落 . 但实际上,除了规范之外,只做以下其中一项是有意义的:
按DST金额向前跳过 . 这是有道理的,因为如果有人忘记在输入中调整DST,您可能会遇到无效值 .
抛出错误或异常,因为该日历时间不存在 . JavaScript没有't do this, but other languages/libraries do. For example, .NET' s
TimeZoneInfo.ConvertTimeToUtc
方法如果你传递一个无效的本地时间将抛出异常 .我想不出任何真实世界的用例,就像Chrome那样向后移动是有意义的 . 它符合ES5规范,但没有任何意义 .
Firefox只是有一个错误,其标签搞砸了,这是also described here .
另外请记住,虽然DST的大多数区域过渡了一个小时,但至少有一个区域只有30分钟(
Australia/Lord_Howe
),而且一些南极洲区域甚至更加陌生 .另一个相关的问题是后退转型的含糊不清 . 由于DST,存在重叠,其中有效的本地时间可以表示两个不同的UTC时刻 . 同样,ES5规范没有说明在这种情况下会发生什么 . 实际上,我们再次发现每个浏览器的行为都不同 . 有些人需要白天时间,因为"standard"是"standard" .
在其他框架中,Python(通过pytz)将抛出异常,而.NET的
TimeZoneInfo
方法将假定"standard"时间 . 像Noda Time这样的图书馆为您提供了选择 . 但在JavaScript中,行为是特定于实现的 .可能是你能做的最好的事情模糊的时间或无效的时间是测试你的输入 . 如果它不明确,请提示您的用户选择两种可能之一 .
考虑
LocalTime(t)
函数的图表,因为它适用于美国太平洋时间(America/Los_Angeles
) .这是一个有效的函数,但是如果你翻转X轴和Y轴,那么你将看到
UTC(t)
的效果,它没有在 spring 前进过渡范围内定义,并且在回退过渡范围内根本不是一个函数 .