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

相關文章
相關標籤/搜索