JavaScript Date.parse 的小坑

TL;DR

new DateDate.parse 在格式化某些日期字符串的时候,时区具备不肯定性,最好用 moment.js 这类工具去处理。html

不肯定的日期字符串

事情的起源是客户跟我说网页上的某个日期老是比实际日期少一天。通过一步步 debug 后发现问题在此:工具

js// 客户时区为美国东部时区夏令时
new Date("2015-03-31")    // Mon Mar 30 2015 20:00:00 GMT-0400 (EDT)

明明写的 31 号,为何生成的对象是 30 号的?由于 new Date 把它解析为 2015-03-31 00:00:00 ,时区为 UTC 。美国东部时区是减 4 小时的,因而就变成了前一天 20:00:00 。debug

那么 new Date 传入的时间字符串有没有规律可循呢?code

混乱的规律

new DateDate.parse 使用的是一样的解析规律,只是一个返回 Date object 另外一个返回毫秒数。为了方便查看结果,如下例子只用 new Date 。但请记住它们遵循同样的规律。htm

new Date 能够传入一个日期字符串来生成对象的,官方规定日期字符串须要符合 RFC2822 或者 ISO8601 的格式。拿上面的日期举个例子,前者能够写成 "Mar 31 2015" 后者能够写成 "2015-03-31" 。对象

若是日期字符串不符合这两种标准,new Date 对结果概不负责……ip

不过就算符合标准了,结果仍是有点不一样的。看几个例子:字符串

jsnew Date("Mar 31 2015")    // Tue Mar 31 2015 00:00:00 GMT-0400 (EDT)
new Date("2015-03-31")     // Mon Mar 30 2015 20:00:00 GMT-0400 (EDT)

RFC2822 的格式若是不带时区,new Date 会当作本地时区处理,而 ISO8601 格式则会当作 UTC 时区处理。get

是有点绕人,但只要记住这个规律不就完了吗?骚年你太天真了…… 由于 ES6 草案为了简化这种状况,规定全部不带时区的字符串都默认为本地时区。注意这是草案,因此结果你懂的。object

解决方案

一种解决方案是每次格式化日期都严格指定时区,以防止各类幺蛾子状况出现,好比:

jsnew Date("2015-03-31T00:00:00-04:00")    // Tue Mar 31 2015 00:00:00 GMT-0400 (EDT)

不过鉴于人都是懒惰的,这种状况交给工具作更靠谱,好比 moment.js 。

jsmoment("2015-03-31").toDate()

参考连接

Date.parse() - JavaScript | MDN

相关文章
相关标签/搜索