案例一:

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

输出:

2005年7月08日上午00:00 GMT-0700 (PST)

案例二:

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

输出:

2005 年 7 月 7 日星期四 17:00:00 GMT-0700 (PST)


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


当前回答

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

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

其他回答

According to http://blog.dygraphs.com/2012/03/javascript-and-dates-what-mess.html the format "yyyy/mm/dd" solves the usual problems. He says: "Stick to "YYYY/MM/DD" for your date strings whenever possible. It's universally supported and unambiguous. With this format, all times are local." I've set tests: http://jsfiddle.net/jlanus/ND2Qg/432/ This format: + avoids the day and month order ambiguity by using y m d ordering and a 4-digit year + avoids the UTC vs. local issue not complying with ISO format by using slashes + danvk, the dygraphs guy, says that this format is good in all browsers.

这种疯狂是有原因的。作为一般规则,如果浏览器可以将日期解释为ISO-8601,它就会这样做。“2005-07-08”就属于这个阵营,因此它被解析为UTC。“july 8, 2005”不能,所以它是用当地时间解析的。

参见JavaScript和日期,真是一团糟!更多信息。

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

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

Until the 5th edition spec came out, the Date.parse method was completely implementation dependent (new Date(string) is equivalent to Date.parse(string) except the latter returns a number rather than a Date). In the 5th edition spec the requirement was added to support a simplified (and slightly incorrect) ISO-8601 (also see What are valid Date Time Strings in JavaScript?). But other than that, there was no requirement for what Date.parse / new Date(string) should accept other than that they had to accept whatever Date#toString output (without saying what that was).

从ECMAScript 2017 (edition 8)开始,实现需要解析dat# toString和dat# toUTCString的输出,但没有指定这些字符串的格式。

截至ECMAScript 2019(版本9),日期#toString和日期#toUTCString的格式已被指定为(分别):

ddd MMM DD YYYY HH:mm:ss ZZ[(时区名)]2018年7月10日星期二18:39:58 GMT+0530(美国标准时间) ddd, DD MMM YYYY HH:mm:ss Ze.g。2018年7月10日星期二13:09:58 GMT

提供2个以上的格式,日期。Parse应该在新的实现中可靠地解析(注意,支持不是普遍存在的,不兼容的实现将继续使用一段时间)。

我建议手动解析日期字符串,并将date构造函数与年、月和日参数一起使用以避免歧义:

// parse a date in yyyy-mm-dd format
function parseDate(input) {

  let 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
}

两者都是正确的,但它们被解释为两个不同时区的日期。所以你比较了苹果和橘子:

// local dates
new Date("Jul 8, 2005").toISOString()            // "2005-07-08T07:00:00.000Z"
new Date("2005-07-08T00:00-07:00").toISOString() // "2005-07-08T07:00:00.000Z"
// UTC dates
new Date("Jul 8, 2005 UTC").toISOString()        // "2005-07-08T00:00:00.000Z"
new Date("2005-07-08").toISOString()             // "2005-07-08T00:00:00.000Z"

我删除了Date.parse()调用,因为它会自动用于字符串参数。我还使用ISO8601格式比较了日期,以便您可以直观地比较本地日期和UTC日期之间的日期。时间相差7小时,这就是时区的差异,这就是为什么你的测试显示了两个不同的日期。

创建这些相同的本地/UTC日期的另一种方法是:

new Date(2005, 7-1, 8)           // "2005-07-08T07:00:00.000Z"
new Date(Date.UTC(2005, 7-1, 8)) // "2005-07-08T00:00:00.000Z"

但我仍然强烈推荐Moment.js,它简单而强大:

// parse string
moment("2005-07-08").format()       // "2005-07-08T00:00:00+02:00"
moment.utc("2005-07-08").format()   // "2005-07-08T00:00:00Z"
// year, month, day, etc.
moment([2005, 7-1, 8]).format()     // "2005-07-08T00:00:00+02:00"
moment.utc([2005, 7-1, 8]).format() // "2005-07-08T00:00:00Z"