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

Mic*_*ael 97 javascript datetime date

我正在尝试将两个日期字符串传递给new Date(t).

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

但是,

new Date("2016-02-16 00:00")
Run Code Online (Sandbox Code Playgroud)

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

new Date("2016-02-16")
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

我做错了什么,或者我应该采取不同的做法?

Joa*_*son 100

这就是ES5.1规范所说的:

缺席时区偏移的值是"Z".

它还说:

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

由于格式需要T日期和时间之间的分隔符,因此有效时间将转到UTC:

> 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)
Run Code Online (Sandbox Code Playgroud)

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

> new Date("2016-02-16 00:00:00")
Tue Feb 16 2016 00:00:00 GMT+0100 (CET)
Run Code Online (Sandbox Code Playgroud)

请注意,ES6 更改了此内容,在文档的相同部分中更改为:

如果不存在时区偏移,则将日期时间解释为本地时间.

打破变化的喜悦.

编辑

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

  • 确实,突破变革的喜悦.在ES7标准的新草案中,[从UTC到当地时间的部分变更被还原](https://github.com/tc39/ecma262/commit/4f4a37a211ed44aeffb31cc3dcbe56096c949154)新标准规定日期应解释为UTC没有指定时区,如果没有指定时区,则应将date-times解释为本地时间. (20认同)
  • 无论是仅日期还是日期时间形式,它们都应该是本地时间.这就是ISO8601的工作原理.将仅限日期的表格解释为午夜UTC是荒谬的,因为永恒的UTC日期在概念上甚至没有意义.ECMA tc39对此进行了激烈辩论.我为当地时间而战,输了.https://github.com/tc39/ecma262/issues/87 (3认同)
  • 另外,请考虑[Moment.js](http://momentjs.com)的一致性和理智性. (2认同)

Sal*_*n A 10

根据规格:

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

并且日期时间字符串格式接受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
Run Code Online (Sandbox Code Playgroud)

摘要:

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


tra*_*r53 7

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

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

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


zan*_*ngw 6

DateParser::Parse()的V8源码为Chrome.

ES5 ISO 8601日期:

[('-'|'+')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)
Run Code Online (Sandbox Code Playgroud)

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

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