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

IT技术 javascript string date datetime time
2021-01-30 06:13:46

在使用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 这样的日期库如何处理日期字符串?

如果你没有注意到,我回答了我自己的问题(为什么?)。

2个回答

要点

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 不考虑任何用户本地日期时间格式,这意味着您不能使用特定于国家或地区的日期时间格式。

短日期(和时间)表格

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

此格式包括仅日期格式:

  • 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')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 的变化

如果MMDD字段不存在“01”,则将其用作值。如果HHmm、 或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()已指定为“实现相关”。

@str——是的,更长的版本,但可以更简洁:Object.prototype.toString.call(d) == '[object Date]' && !isNaN(d)好的,它是 65 个字符 vs 30 个字符,但您只需编写一次。;-)
2021-03-22 06:13:46
isValidDate功能有两个问题:的instanceof一直被认为是一个贫穷的方法来确定一个对象是一个特殊的构造函数的一个实例(见检测在JavaScript中“无效的日期” Date实例),与对象之间的功能,而且一视同仁这不是日期和具有 NaN 时间值的日期。
2021-03-27 06:13:46
@RobG 该示例取自您链接的问题。你会推荐什么?更长的版本
2021-03-28 06:13:46
我想两者都是真的:D
2021-04-06 06:13:46

那么我应该使用哪种日期时间格式?

一般建议是根本不使用内置解析器,因为它不可靠,因此“应该”的答案是“无”。请参阅为什么 Date.parse 给出不正确的结果?

但是,正如 str 所说,您可能可以使用 ECMA-262 中指定的格式和时区:YYYY-MM-DDTHH:mm:ss.sssZ或者YYYY-MM-DDTHH:mm:ss.sss±HH:mm,不要相信任何其他格式。

所有浏览器都支持相同的格式吗?

不。

Mozilla Firefox、Google Chrome、Microsoft Internet Explorer、Microsoft Edge 和 Apple Safari 如何处理日期时间字符串?

不同。ECMA-262 格式以外的任何内容都依赖于实现,并且在解析 ECMA-262 格式时存在错误。

Node.js 呢?

可能再次不同,见上文。

它是否考虑了本地日期格式?例如,如果我住在瑞士并且日期格式是 30.07.2018,我可以使用 new Date('30.07.2018') 吗?

也许。由于它不是标准格式,解析依赖于实现,所以也许,也许不是。

是否考虑了当地时区?

它使用主机时区偏移量,其中字符串被解析为本地并生成使用本地时间显示的字符串。否则,它使用 UTC(内部时间值为 UTC)。

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

Date.parse.toString,或参见我在哪里可以找到有关在 JavaScript 中格式化日期的文档?

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

这里的前 3 个答案之一应该回答这个问题。

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

他们根据默认格式或提供的格式解析它们。阅读源代码(例如fecha.js是一个简单的解析器和格式化程序,代码编写良好,易于遵循)。

解析器不难编写,但尝试猜测输入格式(如内置解析器往往会做的那样)是令人担忧的、不可靠的和跨实现的不一致。所以解析器应该要求提供格式,除非输入字符串是解析器的默认格式。

聚苯乙烯

在 ECMAScript 2019(目前处于草案中)中,实现必须支持解析和格式化的字符串格式发生了变化,但我认为避免内置解析器的一般建议将持续一段时间。

我尽量保持简洁,因为你已经完成了纲要。:-)
2021-03-13 06:13:46
您问题中的几乎所有内容都已经在我的内容中了 :) 除了我更加强调规范和实现的实际作用,而不是一些浏览器除此之外可能会或可能不会做的事情。
2021-03-21 06:13:46