要点
JavaScript 正式支持ISO 8601 扩展格式的简化。格式如下:YYYY-MM-DDTHH:mm:ss.sssZ
. 字母T
是日期/时间分隔符,Z
是指定为Z
(对于 UTC)的时区偏移量,+
或-
后跟时间表达式HH:mm
。该格式的某些部分(例如时间)可以省略。
请注意,年份必须至少有四位数字,月/日/小时/分钟/秒必须恰好有两位数字,而毫秒必须恰好有三位数字。例如,99-1-1
不是有效的日期字符串。
这些是有效日期(时间)字符串的一些示例:
2018-12-30
2018-12-30T20:59
2018-12-30T20:59:00
2018-12-30T20:59:00.000Z
2018-12-30T20:59:00.000+01:00
2018-12-30T20:59:00.000-01:00
当您省略时区偏移时,日期时间被解释为用户本地时间。当您完全省略时间时,日期将被解释为 UTC。
重要提示:根据规范,所有现代和相当老的浏览器和实现都支持全长日期时间格式。
但是,没有时区的日期(时间)字符串的处理存在差异(有关详细信息,请参阅下面的“缺少时区偏移量”)。你应该不是没有时区(状态2018)使用日期时间字符串。而是将一个以毫秒为单位的Unix 时间戳或日期不同部分的单独参数传递给Date
构造函数。
大多数浏览器还支持一些其他格式,但没有指定它们,因此在所有浏览器中的工作方式不同。如果有的话,您应该只使用上面解释的日期时间字符串格式。其他所有格式都可能在其他浏览器甚至同一浏览器的其他版本中崩溃。
如果您遇到Invalid Date
而不是日期对象,您很可能正在使用无效的日期时间字符串。
现在有更多的细节。
日期时间字符串格式
ECMAScript(JavaScript 语言实现的规范)从一开始就支持new Date
(规范)和Date.parse
(规范)中的日期字符串。但是,第一个版本实际上并没有指定日期时间格式。这在 2009 年发生了变化,当时 ES5 引入了日期时间格式的规范。
基础知识
ECMAScript中指定的日期时间字符串格式为简化了的ISO 8601扩展格式。格式如下:YYYY-MM-DDTHH:mm:ss.sssZ
.
YYYY
是公历中 0000 到 9999 年的十进制数字。
-
(连字符)在字符串中出现两次。
MM
是一年中从 01(一月)到 12(十二月)的月份。
DD
是从 01 到 31 的月份中的第几天。
T
字面出现在字符串中,以指示时间元素的开始。
HH
是自午夜以来经过的完整小时数,以两位十进制数字表示,从 00 到 24。
:
(冒号) 在字符串中出现两次。
mm
是从一小时开始的完整分钟数,以 00 到 59 的两位十进制数字表示。
ss
是从 00 到 59 的两位十进制数字表示自分钟开始以来的完整秒数。
.
(点)字面出现在字符串中。
sss
是从秒开始的完整毫秒数,以三位十进制数字表示。
Z
是指定为“Z”(对于 UTC)或“+”或“-”后跟时间表达式的时区偏移量 HH:mm
该规范还提到,如果“字符串不符合 [指定的] 格式,该函数可能会回退到任何特定于实现的启发式或特定于实现的日期格式”,这可能会导致不同浏览器中的日期不同。
ECMAScript 不考虑任何用户本地日期时间格式,这意味着您不能使用特定于国家或地区的日期时间格式。
短日期(和时间)表格
该规范还包括以下更短的格式。
此格式包括仅日期格式:
它还包括“日期-时间”形式,其中包含上述仅日期形式之一,紧接着是以下时间形式之一,并附加可选的时区偏移量:
THH:mm
THH:mm:ss
THH:mm:ss.sss
回退值
[...] 如果MM
或DD
字段不存在,"01"
则用作值。如果HH
、mm
、 或ss
字段不存在"00"
则用作值,而不存在sss
字段的值为"000"
。当不存在时区偏移时,仅日期形式被解释为 UTC 时间,日期时间形式被解释为本地时间。
有关缺少浏览器支持的更多信息,请参阅下面的“缺少时区偏移”。
越界值
格式字符串中的非法值(越界以及语法错误)意味着该格式字符串不是该格式的有效实例。
例如,new Date('2018-01-32')
andnew Date('2018-02-29')
将导致 Invalid Date
.
延长年限
ECMAScript 的日期时间格式还指定了扩展年份,即六位数年份值。这种扩展年份字符串格式的示例如下所示+287396-10-12T08:59:00.992Z
,它表示公元 287396 年的日期。扩展年份可以是正数也可以是负数。
日期API
ECMAScript 指定了广泛的日期对象属性。给定一个有效的日期对象,您可以使用它Date.prototype.toISOString()
来获取有效的日期时间字符串。请注意,时区始终为 UTC。
new Date().toISOString() // "2018-08-05T20:19:50.905Z"
还可以Invalid Date
使用以下函数检测日期对象是否有效或是否有效。
function isValidDate(d) {
return d instanceof Date && !isNaN(d);
}
可以在检测 JavaScript 中的“无效日期”日期实例中找到源代码和更多信息。
例子
有效的日期时间格式
根据规范,以下日期时间格式都是有效的,并且应该适用于所有支持 ES2016 或更高版本的浏览器、Node.js 或其他实现。
2018
2018-01
2018-01-01
2018-01-01T00:00
2018-01-01T00:00:00
2018-01-01T00:00:00.000
2018-01-01T00:00:00.000Z
2018-01-01T00:00:00.000+01:00
2018-01-01T00:00:00.000-01:00
+002018-01-01T00:00:00.000+01:00
无效的日期时间格式
请注意,根据规范,以下示例无效。但是,这并不意味着没有浏览器或其他实现将它们解释为日期。请不要使用以下任何日期时间格式,因为它们是非标准的,并且在某些浏览器或浏览器版本中可能会失败。
2018-1-1 // month and date must be two digits
2018-01-01T0:0:0.0 // hour/minute/second must be two digits, millisecond must be three digits
2018-01-01 00:00 // whitespace must be "T" instead
2018-01-01T00 // shortest time part must have format HH:mm
2018-01-01T00:00:00.000+01 // time zone must have format HH:mm
浏览器支持
今天,每个现代且相当老的浏览器都支持2009 年 ES5 规范引入的日期时间格式。然而,即使在今天(Status 2018),对于没有时区的日期时间字符串也有不同的实现(参见“Missing Time Zone Offset “ 以下)。
如果您需要支持旧浏览器或使用没有时区的字符串,则不应使用日期时间字符串。相反,将自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数
或两个或多个表示不同日期部分的参数传递给Date
构造函数。
缺少时区偏移
ES5.1错误地指出不存在时区偏移的值“Z”
与 ISO 8601 相矛盾。这个错误在ES6 (ES2015) 中被修复并在ES2016 中扩展(参见下面的“对 ECMAScript 规范的更改”)。从 ES2016 开始,没有时区的日期时间字符串被解析为本地时间,而只有日期的字符串被解析为 UTC。
根据这个答案,一些实现从未实现 ES5.1 中指定的行为。其中之一似乎是 Mozilla Firefox。其他似乎符合 ES2016(及更高版本)规范的浏览器包括 Google Chrome 65+、Microsoft Internet Explorer 11 和 Microsoft Edge。当前版本的 Apple Safari (11.1.2)不兼容,因为它错误地将没有时区的日期时间字符串(例如2018-01-01T00:00
)解析为 UTC 而不是本地时间。
传统日期时间格式
ES5 在 2009 年引入了日期时间字符串的规范。在此之前,没有所有浏览器都支持的指定格式。因此,每个浏览器供应商都增加了对不同格式的支持,这些格式通常不适用于不同的浏览器(和版本)。有关古代历史的一个小例子,请参阅日期格式。
大多数浏览器仍然支持这些旧格式,以免破坏旧网站的向后兼容性。但是依赖那些非标准格式是不安全的,因为它们可能会不一致或随时被删除。
Date.prototype.toString()
和 Date.prototype.toUTCString()
ES2018 首次指定了Date.prototype.toString()
和返回的日期格式Date.prototype.toUTCString()
。在此之前,ECMA 规范需要Date
构造函数并Date.parse
正确解析这些方法返回的格式(即使它在 2018 年之前没有指定格式)。
的示例返回值Date.prototype.toString()
可能如下所示:
Sun Feb 03 2019 14:27:49 GMT+0100 (Central European Standard Time)
请注意,括号内的时区名称是可选的,确切的名称是“依赖于实现的”。
Date.prototype.toUTCString()
以类似的格式返回一个日期,Date.prototype.toString()
但时区偏移为零。示例格式可能如下所示:
Sun, 03 Feb 2019 13:27:49 GMT
请注意,,
与Date.prototype.toUTCString()
.
由于这些格式仅在 2018 年才被指定,因此您不应依赖它们在不同的实现(尤其是旧浏览器)中同等工作。
节点.js
Node.js 在 V8 JavaScript 引擎上运行,该引擎也在 Google Chrome 中使用。因此,适用于日期时间字符串格式的相同规范。
由于代码在后端运行,因此用户本地时间不会影响时区,而只会影响服务器上的设置。大多数托管 Node.js 应用程序的平台即服务 (PaaS) 提供商使用 UTC 作为其默认时区。
日期时间库
时刻.js
Moment.js是一个非常流行的库,用于帮助处理 JavaScript 中的日期,它还支持比 ECMAScript 指定的更多格式。此外,Moment.js 还支持基于字符串和任意格式创建日期对象。
卢克森
Luxon支持解析ISO 8601、HTTP、RFC2822、SQL 和任意格式。但仅针对不同的日期时间格式使用不同的函数。
ECMAScript 规范的变化
ECMAScript 规范中有关日期时间字符串格式的显着更改列表。
ES2018 的变化
介绍Date.prototype.toString()
和返回的日期格式的规范Date.prototype.toUTCString()
。
ES2017 的变化
无明显变化。
ES2016 的变化
如果不存在时区偏移量,则日期时间将被解释为本地时间。
当不存在时区偏移时,仅日期形式被解释为 UTC 时间,日期时间形式被解释为本地时间。
在变化ES6(ES2015)
不存在的时区偏移的值为“Z”
。
如果不存在时区偏移量,则日期时间将被解释为本地时间。
来自ECMAScript 2015 中的更正和澄清,可能对兼容性产生影响:
如果不存在时区偏移量,则使用本地时区。5.1 版错误地指出,缺少的时区应解释为"z"
.
有关该更改的更多详细信息,请参阅日期时间字符串格式:与 ES5 不兼容的默认时区差异。
ES5.1 的变化
如果MM
或DD
字段不存在“01”
,则将其用作值。如果HH
、mm
、 或ss
字段不存在“00”
则用作值,而不存在sss
字段的值为“000”
。不存在的时区偏移的值为“Z”
。
ES5 的变化
ECMAScript 规范中首次引入了日期时间字符串格式。
ECMAScript 基于 ISO 8601 扩展格式的简化定义了日期时间的字符串交换格式。格式如下:YYYY-MM-DDTHH:mm:ss.sssZ
还介绍Date.prototype.toISOString()
which 返回指定格式的日期时间字符串。
ES3 的变化
弃用Date.prototype.toGMTString()
,并替换它Date.parse(x.toUTCString())
的部分提的是,这些方法返回的格式必须是由implmentations正确解析的Date.parse
。请注意,返回的格式Date.parse(x.toUTCString())
是“依赖于实现的”。
ES2 的变化
无明显变化。
初始规格:ES1
ES1 引入了用于new Date(value)
和 的日期时间字符串Date.parse(value)
。但是,它没有指定实际的日期(时间)格式,它甚至指出
[...] 产生的valueDate.parse
取决于实现 [...]
该规范还提到
如果x
是任何日期对象 [...],则以下所有表达式都应在该实现 [...] 中产生相同的数值:
- [...]
Date.parse(x.toString())
Date.parse(x.toGMTString())
然而,同时返回的值Date.prototype.toString()
,并Date.prototype.toGMTString()
已指定为“实现相关”。