代码之家  ›  专栏  ›  技术社区  ›  str

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

  •  8
  • str  · 技术社区  · 6 年前

    使用时 new Date Date.parse Invalid Date 而不是日期对象。某些日期格式在一个浏览器中工作,但在其他浏览器中不工作。那么我应该使用哪种日期时间格式呢?

    其他问题:

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

    • 是否考虑了本地日期格式?例如,如果我住在瑞士,日期格式是2018年7月30日,我可以使用 new Date('30.07.2018') ?

    • 是否考虑了当地时区?

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

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

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

    如果你没有注意到,我回答了我自己的问题( why? ).

    2 回复  |  直到 6 年前
        1
  •  28
  •   str    5 年前

    基本要素

    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 timestamp in milliseconds or separate arguments for different parts of the date Date 构造器。

    大多数浏览器还支持其他一些格式,但它们没有指定,因此在所有浏览器中的工作方式不尽相同。 如果需要,您应该只使用上面解释的日期-时间字符串格式。 在其他浏览器中,甚至在同一浏览器的其他版本中,所有其他格式都可能中断。

    如果你碰到 Invalid Date 您很可能使用的不是日期对象,而是无效的日期时间字符串。


    再详细一点。

    日期时间字符串格式

    ECMAScript(JavaScript语言实现的规范)一直支持 new Date ( specification )以及 Date.parse ( specification )从一开始。 但是,第一个版本实际上并没有指定日期时间格式。 这一点在2009年发生了变化,当时ES5引入了日期-时间格式的规范。

    基础知识

    ECMAScript指定 Date Time String Format 作为一个 简化 ISO 8601 Extended Format . 格式如下: YYYY-MM-DDTHH:MM:ss.sssZ .

    • YYYY 是指公历开始前0000年到9999年的十进制数字。
    • - (连字符)在字符串中出现两次。
    • MM 是一年中从1月1日到12日的月份。
    • DD 是从01到31的一个月中的一天。
    • T型 按字面意思出现在字符串中,表示时间元素的开始。
    • HH 是自午夜起已过的完整小时数,以00到24之间的两位十进制数字表示。
    • : (冒号)在字符串中出现两次。
    • mm 从小时开始算起的完整分钟数,以00到59之间的两位小数表示。
    • ss 是自分钟开始后的完整秒数,以00到59之间的两个十进制数字表示。
    • . (点)按字面意思出现在字符串中。
    • sss 是自第二个小数位数开始后的完整毫秒数。
    • Z轴 时区偏移量指定为“Z”(表示UTC)或“+”或“-”,后跟时间表达式 时:分

    规范也 mentions 如果“字符串不符合[指定的]格式,则函数可能会返回到任何特定于实现的启发式或特定于实现的日期格式”,这可能会导致不同浏览器中的日期不同。

    ECMAScript不考虑任何用户本地日期时间格式,这意味着您不能使用特定于国家或地区的日期时间格式。

    短日期(和时间)表单

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

    此格式仅包括日期表单:

    • YYYY-MM
    • YYYY-MM-DD

    它还包括“日期-时间”表单,该表单由一个以上仅日期的表单组成,紧跟其后的是一个附加了可选时区偏移的以下时间表单:

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

    回退值

    […]如果 毫米 尽职调查 字段不存在 "01" 用作值。如果 小时 , 毫米 ,或 党卫军 字段不存在 "00" 被用作 sss公司 字段是 "000" . 如果不存在时区偏移,则仅日期窗体将被解释为UTC时间,而日期时间窗体将被解释为本地时间。

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

    超出范围的值

    格式字符串中的非法值(越界以及语法错误)表示格式字符串不是此格式的有效实例。

    例如, new Date('2018-01-32') new Date('2018-02-29') 将导致 无效日期 .

    延长年限

    ECMAScript的日期时间格式还指定 extended years 六位数的年份值。 这种扩展年份字符串格式的示例如下 +287396-10-12T08:59:00.992Z 它表示公元287396年的一个日期。 延长的年份可以是正的,也可以是负的。

    日期API

    ECMAScript指定了 date object properties . 给定一个有效的日期对象,您可以使用 Date.prototype.toISOString() 获取有效的日期时间字符串。 请注意,时区始终是UTC。

    new Date().toISOString() // "2018-08-05T20:19:50.905Z"
    

    也可以检测日期对象是有效的还是 无效日期 使用以下函数。

    function isValidDate(d) {
      return d instanceof Date && !isNaN(d);
    }
    

    源和更多信息可以在 Detecting an “invalid date” Date instance in 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
    

    浏览器支持

    今天, every modern and reasonably old browser supports the date time format 这是在2009年ES5规范中引入的。 然而,即使在今天(状态2018),没有时区的日期-时间字符串也有不同的实现(参见下面的“缺少时区偏移量”)。 如果需要支持较旧的浏览器或使用不带时区的字符串,则不应使用日期-时间字符串 . 相反,通过 number of milliseconds since January 1, 1970, 00:00:00 UTC two or more arguments representing the different date parts 日期 构造器。

    缺少时区偏移

    ES5.1标准 incorrectly 声明缺少时区偏移量的值为 “Z” 这与ISO 8601相矛盾。 这个错误是在 ES6 (ES2015) 一直延伸到 ES2016 (请参阅下面的“对ECMAScript规范的更改”)。 自ES2016起,不带时区的日期-时间字符串将被解析为本地时间,而仅日期字符串将被解析为UTC。

    根据 this answer ,有些实现从未实现ES5.1中指定的行为。 其中之一似乎是Mozilla Firefox。 其他似乎符合ES2016(及更高版本)规范的浏览器有Google Chrome 65+、Microsoft Internet Explorer 11和Microsoft Edge。 苹果Safari(11.1.2)的当前版本是 兼容,因为它错误地解析没有时区的日期-时间字符串(例如。 2018-01-01T00:00 )作为UTC而不是当地时间。

    传统日期时间格式

    ES5在2009年引入了日期-时间字符串规范。 在此之前,所有浏览器都不支持指定的格式。 因此,每个浏览器供应商都增加了对不同格式的支持,而这些格式在不同的浏览器(和版本)中往往不起作用。 有关古代历史的一个小例子,请参见 date-formats .

    大多数浏览器仍然支持这些传统格式,以便不破坏旧网站的向后兼容性。 但依赖这些非标准格式是不安全的,因为它们可能不一致或随时被删除。

    Date.prototype.toString() Date.prototype.toUTCString()

    ES2018首次指定了返回的日期格式 Date.prototype.toString() Date.prototype.toUTCString() . 在此之前,ECMA规范要求 日期 构造器和 日期.parse 正确解析这些方法返回的格式(即使它在2018年之前没有指定格式)。

    返回值示例 Date.prototype.toString() 可能是这样的:

    Sun Feb 03 2019 14:27:49 GMT+0100 (Central European Standard Time)
    

    请注意,括号内的时区名称是可选的,确切的名称是“依赖于实现”。

    Date.prototype.toutstring() 以类似的格式返回日期 Date.prototype.toString() 但时区偏移量为零。示例格式可能如下所示:

    Sun, 03 Feb 2019 13:27:49 GMT
    

    注意这里有一个逗号 , 工作日和日后月份与 Date.prototype.toutstring() .

    由于这些格式在2018年才被指定,所以您不应该依赖它们在不同的实现中(尤其是较旧的浏览器)的平等工作。

    Node.js节点

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

    日期时间库

    矩.js

    Moment.js 是一个非常流行的库,可以帮助处理JavaScript中的日期,而且 supports more formats 而不是ECMAScript指定的。 此外,Moment.js还支持 creating date objects based on a string and a arbitrary format .

    卢克逊

    Luxon 支架 parsing ISO 8601、HTTP、RFC2822、SQL和任意格式。但只对不同的日期时间格式使用不同的函数。

    对ECMAScript规范的更改

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

    变化 ES2018

    介绍了由 Date.prototype.toString() Date.prototype.toutstring() .

    变化 ES2017

    没有明显的变化。

    变化 ES2016年

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

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

    变化 ES6(ES2015年)

    缺少时区偏移量的值为 Z轴 .

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

    Corrections and Clarifications in ECMAScript 2015 with Possible Compatibility Impact :

    如果不存在时区偏移,则使用本地时区。第5.1版错误地指出,丢失的时区应解释为 "z" .

    Date Time String Format: default time zone difference from ES5 not web-compatible 更多关于这一变化的细节。

    变化 ES5.1

    如果 毫米 尽职调查 字段不存在 “01” 用作值。如果 小时 , 毫米 ,或 党卫军 字段不存在 “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()) 在提到这些方法返回的格式必须通过 日期.parse . 注意,返回的格式 Date.parse(x.toutString()) 是“依赖于实现”。

    变化 ES2

    没有明显的变化。

    初始规格: ES1

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

    […]产生的价值 日期.parse 依赖于实现[…]

    规范还提到

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

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

    但是,两者的返回值 Date.prototype.toString() Date.prototype.toGMTString() 被指定为“依赖于实现”。

        2
  •  1
  •   RobG    6 年前

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

    一般建议不要使用内置解析器,因为它是不可靠的,所以“应该”的答案是“无”。见 Why does Date.parse give incorrect results?

    不过,正如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呢?

    可能再次不同,见上文。

    是否考虑了本地日期格式?例如,如果我住在瑞士,日期格式是2018年7月30日,我可以使用新日期(“2018年7月30日”)吗?

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

    是否考虑了当地时区?

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

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

    Date.parse.toString ,或查看 Where can I find documentation on formatting a date in JavaScript?

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

    前三个答案之一 here 应该回答这个问题。

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

    它们基于默认格式或提供的格式解析它们。读取源代码(例如。 fecha.js 是一个简单的解析器和格式化程序,具有编写良好、易于理解的代码)。

    解析器并不难写,但是尝试猜测输入格式(就像内置解析器所做的那样)在实现之间是充满了麻烦、不可靠和不一致的。所以解析器应该要求提供格式,除非输入字符串是解析器的默认格式。

    附言

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