javascript new Date() 构造函数对相同不同格式字符串的不明确行为
Ambiguous behavior of javascript new Date() constructor for same different formatted string
我当地的时区是(UTC+06:00) Dhaka
。在我自己的时区,我没有发现这个问题。但是在我的电脑中将时区更改为 (UTC -12:00) International Date Line West
,
new Date(["2014","01","01"])
给我输出 Wed Jan 01 2014 00:00:00 GMT-1200 (GMT-12:00)
.
new Date("2014-01-01")
给我输出 Tue Dec 31 2013 12:00:00 GMT-1200 (GMT-12:00)
.
为什么会这样?
["2014","01","01"]
和 "2014-01-01"
不应该给出相同的输出吗?
注意 GMT 时间是 -1200。当您指定日期时,我相信它从那天的午夜开始。因为你说的是 2014-01-01,它从那天的午夜减去 12 小时,在 12:00PM.
给你 2013-12-31
这是由于 new Date("2014-01-01")
是通过日期解析创建的,日期解析将此日期视为 UTC,然后应用时区,但 new Date(["2014","01","01"])
被视为每个参数的文字值您的时区的构造函数。尽管如以下评论之一所述,格式 new Date(["2014","01","01"])
不符合 RFC,因此会根据浏览器提供不同的结果。
来自:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
Note: Parsing of date strings with the Date constructor (and Date.parse(), which works the same way) is strongly discouraged due to browser differences and inconsistencies. Support for RFC 2822 format strings is by convention only. Support for ISO 8601 formats differs in that date-only strings (e.g. "1970-01-01") are treated as UTC, not local.
也许您想要的是 new Date(Date.UTC(2014,01,01));
Date.UTC 以创建不受用户配置约束的一致日期。
几件事:
Date
构造函数不接受数组。参见 the specification, and the MDN docs。任何此类津贴都是特定于实现的。例如,new Date(["2014","01","01"])
将在 Chrome 中工作,因为 Chrome 作者决定允许它,但在 Edge 中它给出了 Invalid Date
,因为它不是规范所要求的。 (Date.UTC(array)
也是一样。)
如果您有单独的日期部分,您应该将它们直接传递给构造函数。请注意,在这种形式的构造函数中,月份范围为 0 到 11,因此您必须从第二个参数中减去一个。
new Date(2014, 0, 1)
当您使用上面的形式时,参数旨在根据 当地时间 - 即为代码执行的环境(浏览器环境中的用户时区,或 Node.js 环境中的服务器时区)。时间参数(小时、分钟、秒、毫秒)默认为 0
,因此这是当地时区的午夜,或 2014-01-01T00:00:00.000
.
如果您打算传递基于 UTC 的参数,请使用 Date.UTC
函数,并将结果传递回 Date
构造函数,如:
new Date(Date.UTC(2014, 0, 1))
这会将日期对象设置为午夜 UTC,或 2014-01-01T00:00:00.000Z
。
当您将 字符串 传递给日期构造函数时,首先会尝试对其进行解析 according to rules defined in the specification。如果它不能被规范的规则解析,那么它可以以特定于实现的方式解析。
规范定义 YYYY-MM-DD
格式的字符串(没有任何时间部分) 将被解析为 UTC。这偏离了 ISO-8601,这就是为什么您在调用 new Date("2014-01-01")
时看到不同结果的原因。它被解释为好像您通过了 2014-01-01T00:00:00.000Z
(UTC)。
Date
对象本身只跟踪一个值,即自 Unix 纪元以来的毫秒数,即 1970-01-01T00:00:00.000Z
(UTC)。您可以通过调用 .valueOf()
或 .getTime()
来查看此值。因此,当您使用任何被视为本地时间的形式进行解析时,在解析时 会发生转换 ,从本地时间到 UTC。
之后,当您执行任何需要本地时间输出的操作时,例如调用 .toString()
,或使用 .getDate()
、.getHours()
等函数,执行从基于 UTC 的内部时间戳到本地时间的另一次转换。
在某些环境中,当您 console.log
一个 Date
对象时,您也会看到转换发生,就像您调用 .toString()
一样。在其他情况下,您将看到基于 UTC 的输出,就像您调用 .toISOString()
一样。控制台输出是特定于实现的。
我当地的时区是(UTC+06:00) Dhaka
。在我自己的时区,我没有发现这个问题。但是在我的电脑中将时区更改为 (UTC -12:00) International Date Line West
,
new Date(["2014","01","01"])
给我输出 Wed Jan 01 2014 00:00:00 GMT-1200 (GMT-12:00)
.
new Date("2014-01-01")
给我输出 Tue Dec 31 2013 12:00:00 GMT-1200 (GMT-12:00)
.
为什么会这样?
["2014","01","01"]
和 "2014-01-01"
不应该给出相同的输出吗?
注意 GMT 时间是 -1200。当您指定日期时,我相信它从那天的午夜开始。因为你说的是 2014-01-01,它从那天的午夜减去 12 小时,在 12:00PM.
给你 2013-12-31这是由于 new Date("2014-01-01")
是通过日期解析创建的,日期解析将此日期视为 UTC,然后应用时区,但 new Date(["2014","01","01"])
被视为每个参数的文字值您的时区的构造函数。尽管如以下评论之一所述,格式 new Date(["2014","01","01"])
不符合 RFC,因此会根据浏览器提供不同的结果。
来自:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
Note: Parsing of date strings with the Date constructor (and Date.parse(), which works the same way) is strongly discouraged due to browser differences and inconsistencies. Support for RFC 2822 format strings is by convention only. Support for ISO 8601 formats differs in that date-only strings (e.g. "1970-01-01") are treated as UTC, not local.
也许您想要的是 new Date(Date.UTC(2014,01,01));
Date.UTC 以创建不受用户配置约束的一致日期。
几件事:
Date
构造函数不接受数组。参见 the specification, and the MDN docs。任何此类津贴都是特定于实现的。例如,new Date(["2014","01","01"])
将在 Chrome 中工作,因为 Chrome 作者决定允许它,但在 Edge 中它给出了Invalid Date
,因为它不是规范所要求的。 (Date.UTC(array)
也是一样。)如果您有单独的日期部分,您应该将它们直接传递给构造函数。请注意,在这种形式的构造函数中,月份范围为 0 到 11,因此您必须从第二个参数中减去一个。
new Date(2014, 0, 1)
当您使用上面的形式时,参数旨在根据 当地时间 - 即为代码执行的环境(浏览器环境中的用户时区,或 Node.js 环境中的服务器时区)。时间参数(小时、分钟、秒、毫秒)默认为
0
,因此这是当地时区的午夜,或2014-01-01T00:00:00.000
.如果您打算传递基于 UTC 的参数,请使用
Date.UTC
函数,并将结果传递回Date
构造函数,如:new Date(Date.UTC(2014, 0, 1))
这会将日期对象设置为午夜 UTC,或
2014-01-01T00:00:00.000Z
。当您将 字符串 传递给日期构造函数时,首先会尝试对其进行解析 according to rules defined in the specification。如果它不能被规范的规则解析,那么它可以以特定于实现的方式解析。
规范定义
YYYY-MM-DD
格式的字符串(没有任何时间部分) 将被解析为 UTC。这偏离了 ISO-8601,这就是为什么您在调用new Date("2014-01-01")
时看到不同结果的原因。它被解释为好像您通过了2014-01-01T00:00:00.000Z
(UTC)。Date
对象本身只跟踪一个值,即自 Unix 纪元以来的毫秒数,即1970-01-01T00:00:00.000Z
(UTC)。您可以通过调用.valueOf()
或.getTime()
来查看此值。因此,当您使用任何被视为本地时间的形式进行解析时,在解析时 会发生转换 ,从本地时间到 UTC。之后,当您执行任何需要本地时间输出的操作时,例如调用
.toString()
,或使用.getDate()
、.getHours()
等函数,执行从基于 UTC 的内部时间戳到本地时间的另一次转换。在某些环境中,当您
console.log
一个Date
对象时,您也会看到转换发生,就像您调用.toString()
一样。在其他情况下,您将看到基于 UTC 的输出,就像您调用.toISOString()
一样。控制台输出是特定于实现的。