为什么不是" 2016-02-16"等于" 2016-02-16 00:00"?

时间:2016-02-17 05:06:19

标签: javascript date datetime

我试图将两个日期字符串都传递给new Date(t)

我希望两个字符串代表相同的时间,毕竟,如果我省略时间,那不应该是那天的午夜吗?

但是,虽然,

new Date("2016-02-16 00:00")

按预期返回2016-02-16,午夜,当地时间,

new Date("2016-02-16")

返回2016-02-16,午夜UTC,这是错误的,或者至少不是我预期的另一个字符串解析的内容。

我会理解,如果它们都具有相同的行为,无论是将时间作为本地时间还是作为UTC返回,但为什么它们返回不同的东西似乎非常不一致。

作为一种解决方法,每当我遇到没有相应时间戳的日期时,我都可以附加" 00:00"为了获得一致的行为,但似乎这是相当脆弱的。

我从INPUT元素中获取此值,类型为' datetime-local'因此,我必须解决页面元素返回的值,这似乎特别不一致。

我做错了什么,或者我应该做些不同的事情?

5 个答案:

答案 0 :(得分:100)

这是ES5.1 specification所说的:

  

缺席时区偏移的值为“Z”。

它还说:

  

该函数首先尝试根据日期时间字符串格式(15.9.1.15)中调出的规则解析字符串的格式。如果String不符合该格式,则该函数可以回退到任何特定于实现的启发式或特定于实现的日期格式。

由于格式在日期和时间之间需要> new Date("2016-02-16T00:00:00") Tue Feb 16 2016 01:00:00 GMT+0100 (CET) > new Date("2016-02-16") Tue Feb 16 2016 01:00:00 GMT+0100 (CET) 分隔符,因此有效时间为UTC:

> new Date("2016-02-16 00:00:00")
Tue Feb 16 2016 00:00:00 GMT+0100 (CET)

...在node.js中,无效时间(没有T分隔符)似乎转到特定于实现的本地时间:

{{1}}

请注意,ES6 已更改,在同一part of the documentation中更改为:

  

如果没有时区偏移,则将日期时间解释为当地时间。

breaking changes的快乐。

修改

根据TC39,规范应被解释为没有时区的日期和时间字符串(例如" 2016-02-16T00:00:00")被视为本地(根据ISO 8601),但仅限日期字符串(例如" 2016-02-16")作为UTC(与ISO 8601不一致)。

答案 1 :(得分:10)

根据specifications

  

该函数首先尝试解析String的格式   根据日期时间字符串格式中调出的规则   (15.9.1.15)。如果String不符合那种格式的话   函数可以回退到任何特定于实现的启发式或   特定于实现的日期格式。

Date Time String Formats接受2016-02-16作为有效日期

  

此格式包含仅限日期的表格:

     

YYYY
  YYYY-MM
  YYYY-MM-DD

     

[...]如果不存在HH,mm或ss字段,则使用“00”作为值   并且缺席的sss字段的值是“000”。缺席的价值   时区偏移量为“Z”。

因此2016-02-16会转换为2016-02-16T00:00:00.000Z

另一个日期2016-02-16 00:00不符合格式,因此其解析是特定于实现的。显然,此类日期被视为具有本地时区,您的示例日期将根据时区返回不同的值:

/* tz = +05:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-15T19:00:00.000Z
/* tz = -08:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-16T08:00:00.000Z

要点:

  • 对于符合日期时间格式,行为定义明确 - 在没有时区偏移的情况下,日期字符串被视为UTC(ES5)或本地(ES6)。
  • 对于不符合日期时间格式,行为是特定于实现的 - 在没有时区偏移的情况下,通常的行为是将日期视为本地。
  • 事实上,实施可以选择返回NaN而不是尝试来解析不合格的日期。只需在Internet Explorer 11中测试您的代码;)

答案 2 :(得分:7)

您可能会遇到ES5,ES6实施与预期结果之间的差异。在MDN上每Date.parse,"特别是在不同的ECMAScript实现中,其中字符串如" 2015-10-12 12:00:00"可以解析为NaN,UTC或当地时区"很重要。

Firefox 44和IE 11中的附加测试显示它们都返回new Date("2016-02-16 00:00")的日期对象,该对象在尝试获取日期组件值时返回NaN,其toString值为 "无效日期" (不是" NaN")。因此附加" 00:00获得一致的行为"可以在不同的浏览器中轻松破解。

如其他答案中所述,new Date("2016-02-16")默认使用零时区偏移,产生午夜UTC而不是本地。

答案 3 :(得分:6)

Chrome的每DateParser::Parse()个V8源代码。

  

ES5 ISO8601日期:

     

[('-'|'+')yy]yyyy[-MM[-DD]][THH:mm[:ss[.sss]][Z|(+|-)hh:mm]]

     

无符号数后跟':'是时间值,并添加到TimeComposer。

     如果缺少

时区默认为Z.

> new Date("2016-02-16 00:00")
  Tue Feb 16 2016 00:00:00 GMT+0800 (China Standard Time)
  

匹配两种格式的字符串(例如1970-01-01)将被解析为ES5日期时间字符串 - 这意味着它将默认为UTC time-zon e。如果遵循ES5规范,这是不可避免的。

> new Date("2016-02-16")
Tue Feb 16 2016 08:00:00 GMT+0800 (China Standard Time)

答案 4 :(得分:3)

  

返回2016-02-16,午夜UTC,这是错误的,或者至少不是我预期的另一个字符串解析的内容。

它将时区偏移量添加到00:00

new Date("2016-02-16")输出Tue Feb 16 2016 05:30:00 GMT+0530 (India Standard Time)

我的时区是IST,偏移值(以分钟为单位)+330,所以它增加了330分钟到00:00。

根据ecma-262, section 20.3.3.2 Date.parse ( string )

  

如果ToString导致突然完成,则完成记录为   马上回来了。否则,parse会解释生成的String   作为日期和时间;它返回一个数字,UTC时间值   对应日期和时间。 String可以解释为a   取决于当地时间,UTC时间或某个其他时区的时间   关于字符串的内容。

当您明确设置时间单位new Date("2016-02-16 00:00")时,它将使用设置为hoursminutes

其他,如2 0.3.1.16

中所述
  

如果不存在时区偏移,则将日期时间解释为a   当地时间。