一尘不染

JavaScript中有效的日期时间字符串是什么?

javascript

使用new DateDate.parse在JavaScript中使用时,我不能只传递任意日期格式。根据格式的不同,我得到的日期可能会不同,甚至Invalid Date会得到日期对象。某些日期格式只能在一种浏览器中使用,而不能在其他浏览器中使用。那么我应该使用哪种日期时间格式?

其他问题:

  • 所有浏览器都支持相同格式吗?Mozilla Firefox,Google Chrome,Microsoft Internet Explorer,Microsoft Edge和Apple Safari如何处理日期时间字符串?那Node.js呢?

  • 是否考虑当地日期格式?例如,如果我居住在瑞士且日期格式为30.07.2018,我可以使用new Date('30.07.2018')吗?

  • 是否考虑当地时区?

  • 如何从日期对象获取日期时间字符串?

  • 如何检测无效的日期时间字符串?

  • 像Moment.js这样的日期库如何处理日期字符串?

万一您没有注意到,我回答了我自己的问题(为什么?)。


阅读 542

收藏
2020-04-25

共1个答案

一尘不染

要点

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语言实现的规范)一直在newDate规范和Date.parse规范中支持日期字符串。但是,第一个版本实际上并未指定日期时间格式。在2009年ES5引入了日期时间格式规范后,情况发生了变化。

基础

ECMAScript将日期时间字符串格式指定为ISO8601扩展格式的简化形式。格式如下:。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不考虑任何用户本地日期时间格式,这意味着您不能使用国家或地区特定的日期时间格式。

短日期(和时间)表格

该规范还包括以下较短的格式。

此格式包括仅日期形式:

  • YYYY
  • YYYY-MM
  • YYYY-MM-DD

它还包括“日期时间”格式,该格式由上述仅日期格式之一构成,后跟以下时间格式之一,并附加了可选的时区偏移量:

  • THH:mm
  • THH:mm:ss
  • THH:mm:ss.sss

后备值

[…]如果MMDD字段不存在,"01"则用作值。如果HHmm或者ss字段不存在"00"被用作值和一个缺席值sss字段是"000"。如果不存在时区偏移,则仅日期格式将被解释为UTC时间,而日期时间格式将被解释为本地时间。

有关缺少浏览器支持的更多信息,请参见下面的“缺少时区偏移”。

超出界限的值

格式字符串中的非法值(越界以及语法错误)意味着该格式字符串不是该格式的有效实例。

例如,new Date('2018-01-32')new 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中检测“无效日期”Date实例中找到源和更多信息。

例子

有效的日期时间格式

根据规范,以下日期时间格式均有效,并且应在每种浏览器,Node.js或支持ES2016或更高版本的其他实现中使用。

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),对于不带时区的日期时间字符串也有不同的实现方式(请参阅“缺少时区偏移量”) ”)。
如果您需要支持较旧的浏览器或使用不带时区的字符串,则不应使用日期时间字符串 。相反,传递的毫秒数自1970年1月1日00:00:00UTC或代表不同的日期部分两个或多个参数的Date构造函数。

缺少时区偏移

ES5.1 错误地指出缺少时区偏移的值“Z”与ISO 8601相矛盾。此错误已在ES6(ES2015)中得到修复,并在ES2016中得到扩展(请参见下面的“对ECMAScript规范的更改”)。从ES2016开始,不带时区的日期时间字符串将解析为本地时间,而仅日期字符串将解析为UTC。

根据此答案,某些实现从未实现过ES5.1中指定的行为。其中之一似乎是MozillaFirefox。其他似乎符合ES2016(及更高版本)规范的浏览器是Google Chrome 65 +,Microsoft Internet
Explorer 11和Microsoft Edge。当前版本的AppleSafari(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年才指定,因此您不应该依赖它们在不同的实现方式(尤其是较旧的浏览器)中同样有效地工作。

Node.js

Node.js在V8 JavaScript引擎上运行,该引擎也在Google Chrome中使用。因此 ,适用于日期时间字符串格式的相同规范。
由于代码在后端运行,因此用户本地时间不会影响时区,而只会影响服务器上的设置。托管Node.js应用程序的大多数平台即服务(PaaS)提供程序都使用UTC作为其默认时区。

日期时间库

Moment.js

Moment.js是一个非常流行的库,可帮助处理JavaScript中的日期,并且它还支持ECMAScript指定[更多格式。此外,Moment.js还支持[基于字符串和任意格式创建日期对象。

Luxon

Luxon支持解析ISO 8601,HTTP,RFC2822,SQL和任意格式。但只能对不同的日期时间格式使用不同的功能。

ECMAScript规范的更改

ECMAScript规范中有关日期时间字符串格式的显着更改的列表。

ECMAScript规范中有关日期时间字符串格式的显着更改的列表。

ES2018的变化

介绍由Date.prototype.toString()和返回的日期格式的规范Date.prototype.toUTCString()

ES2017中的更改

没有明显的变化。

ES2016的变化

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

如果不存在时区偏移,则仅日期格式将被解释为UTC时间,而日期时间格式将被解释为本地时间。

ES6的变更(ES2015)

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

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

摘自ECMAScript 2015中的更正和澄清,可能会对兼容性产生影响:

如果不存在时区偏移,则使用本地时区。5.1版错误地指出缺少的时区应解释为”z”。

有关该更改的更多详细信息,请参见日期时间字符串格式:与ES5不兼容的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()了以指定格式返回日期时间字符串的方法。

ES3的变化

在提到的这些部分中弃用Date.prototype.toGMTString()并替换Date.parse(x.toUTCString())为这些方法所返回的格式必须可以通过实现来正确地解析Date.parse。请注意,由返回的格式Date.parse(x.toUTCString())是“与实现有关的”。

ES2的变化

没有明显的变化。

初始规格:ES1

ECMAScript规范中有关日期时间字符串格式的显着更改的列表。

ES2018的变化

介绍由Date.prototype.toString()和返回的日期格式的规范Date.prototype.toUTCString()

ES2017中的更改

没有明显的变化。

ES2016的变化

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

如果不存在时区偏移,则仅日期格式将被解释为UTC时间,而日期时间格式将被解释为本地时间。

ES6的变更(ES2015)

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

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

摘自ECMAScript 2015中的更正和澄清,可能会对兼容性产生影响:

如果不存在时区偏移,则使用本地时区。5.1版错误地指出缺少的时区应解释为”z”。

有关该更改的更多详细信息,请参见日期时间字符串格式:与ES5不兼容的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()了以指定格式返回日期时间字符串的方法。

ES3的变化

在提到的这些部分中弃用Date.prototype.toGMTString()并替换Date.parse(x.toUTCString())为这些方法所返回的格式必须可以通过实现来正确地解析Date.parse。请注意,由返回的格式Date.parse(x.toUTCString())是“与实现有关的”。

ES2的变化

没有明显的变化。

初始规格:ES1

ES1引入了在newDate(value)和中使用的日期时间字符串Date.parse(value)。但是,它没有指定实际的日期(时间)格式,甚至指出

[…]产生的价值Date.parse取决于实现[…]

规范中还提到

如果x是任何Date对象[…],则以下所有表达式在该实现中应产生相同的数值:[…]

  • […]
  • Date.parse(x.toString())
  • Date.parse(x.toGMTString())

然而,同时返回的值Date.prototype.toString(),并Date.prototype.toGMTString()已指定为“实现相关”。

2020-04-25