为什么Date.parse会给出不正确的结果?

Case One:

new Date(Date.parse("Jul 8, 2005"));

输出。

Fri Jul 08 2005 00:00:00 GMT-0700 (PST)

Case Two:

new Date(Date.parse("2005-07-08"));

输出。

Thu Jul 07 2005 17:00:00 GMT-0700 (PST)


为什么第二个解析是不正确的?

解决办法

在第5版规范出来之前,Date.parse方法完全取决于实现new Date(string)等同于Date.parse(string),只是后者返回一个数字而不是一个Date)。在第五版规范中,增加了支持简化的(略微不正确) ISO-8601的要求(也见什么是JavaScript中有效的日期时间字符串?)。但是除此之外,没有要求Date.parse/new Date(string)应该接受什么,只是说他们必须接受任何Date#toString*的输出(没有说是什么)。

从ECMAScript 2017(第8版)开始,要求实现者对Date#toStringDate#toUTCString的输出进行解析,但没有规定这些字符串的格式。

从ECMAScript 2019(第9版)开始,Date#toStringDate#toUTCString的格式被指定为(分别)。

  1. ddd MMM DD YYYY HH:mm:ss ZZ [(时区名称)]
    例如:Tue Jul 10 2018 18:39:58 GMT+0530 (IST)
  2. ddd, DD MMM YYYY HH:mm:ss Z
    例如:Tue 10 Jul 2018 13:09:58 GMT

提供了另外两种格式,Date.parse应该在新的实现中可靠地解析这些格式(注意,支持并不是无处不在的,不符合要求的实现仍将使用一段时间)。

我建议手动解析日期字符串,并使用带有年、月、日参数的Date构造函数,以避免歧义。

// parse a date in yyyy-mm-dd format
function parseDate(input) {
  var parts = input.split('-');
  // new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
  return new Date(parts[0], parts[1]-1, parts[2]); // Note: months are 0-based
}
评论(8)

这是有方法的。一般来说,如果浏览器能够将一个日期解释为ISO-8601,它就会这样做。"2005-07-08"属于这个阵营,所以它被解析为UTC。

参见JavaScript和日期,真是一团糟!以了解更多。

评论(1)

虽然CMS是正确的,在解析方法中传递字符串通常是不安全的,但新的ECMA-262第五版(又称ES5)规范在15.9.4.2节中建议Date.parse()实际上应该处理ISO格式的日期。 旧的规范则没有这样的要求。 当然,旧的浏览器和一些当前的浏览器仍然没有提供这种ES5功能。

你的第二个例子并没有错。 正如Date.prototype.toISOString()所暗示的,它是以UTC为单位的指定日期,但以你的本地时区表示。

评论(2)