跳到主要內容
黯羽輕揚每天積累一點點

JS 日期時間串格式

免費2016-10-01#JS#JS日期字符串#JS日期格式化#JavaScript date string#js date format

兼容性最好的時間串格式、ES5.1 標準時間串格式、千萬不要用的時間串格式

一。new Date()

據說有 4 種方式:

new Date();
new Date(value);
new Date(dateString);
new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);

第 1 種用來取時間戳:

// get ts
var now = Date.now || function() {
    return new Date().getTime();
};

第 2 種把時間戳轉 Date 對象:

// ts to Date
var ts2Date = function(ts) {
    return new Date(ts);
};

第 3 種把日期時間字符串轉 Date 對象:

// string to Date
// eg.  '2016/10/01 12:01:02'
//      '2016/10/01'
var str2Date = function(str) {
    return new Date(str);
};

第 4 種一般不用,因為第 4 種有一個很難受的問題(month0-11):

// set Date
// eg.  2016, 9, 1, 12, 1, 2
//      2016, 9, 1
var setDate = function(y, m, d, h, mm, s, ms) {
    return new Date(y, m, d, h, mm, s, ms);
};
// getter/setter 中,month 是 0-11
var date = new Date();  // 今天是 2016-10-01
date.getMonth();    // 9
date.setMonth(10);
date.toString();    // Tue Nov 01 2016 11:46:58 GMT+0800 (China Standard Time)

第 4 種方法內部用的可能是 setter,所以 month0 開始

比較有用的是第 3 種,因為一般需要處理的日期串都是 ISO 標準格式,比如 2016-10-01 12:01:02,但這在 JS 中是非標準的

二。日期時間串格式

非標準格式

先看這兩個東西:

// new 一個 0 區時間
new Date('2016-10-01'); // Sat Oct 01 2016 08:00:00 GMT+0800 (China Standard Time)
// new 一個當前時區時間
new Date('2016/10/01'); // Sat Oct 01 2016 00:00:00 GMT+0800 (China Standard Time)

第二個正確,第一個多了 8 小時,瀏覽器認為第一種傳入的是 0 區時間,就為東八區用戶私自加了 8 小時,分別等價於:

// Sat Oct 01 2016 08:00:00 GMT+0800 (China Standard Time)
new Date('01 October, 2016 GMT+0000');
// Sat Oct 01 2016 00:00:00 GMT+0800 (China Standard Time)
new Date('01 October, 2016 GMT+0800');

所以千萬不要用yyyy-MM-dd,就算非常確定想要 new 個 0 區時間,也不應該這麼做,因為別人可能看不懂,如果真想要 new 個 0 區時間,應該用其等價格式(帶有 GMT 時區標識的)

添上時間 'HH:mm:ss' 再試試:

// new 一個 0 區時間
// Sat Oct 01 2016 12:01:02 GMT+0800 (China Standard Time)
new Date('2016-10-01 12:01:02');
// new 一個當前時區時間
// Sat Oct 01 2016 12:01:02 GMT+0800 (China Standard Time)
new Date('2016/10/01 12:01:02');

竟然一致了,但是Safari(包括 IOS Safari)不支持yyyy-MM-dd HH:mm:ss 格式,Safari 從開始到現在(2016-10-01)都不支持這種格式,因為是非規範的,可能不打算支持

雖然 yyyy/MM/dd HH:mm:ss 也是非規範的,但因為歷史悠久,包括 IE6 在內的所有瀏覽器都支持該格式

所以,得到廣泛支持的非標準格式有兩個:

// eg. 2016/10/01 12:01:02
yyyy/MM/dd HH:mm:ss
// eg. 01 October, 2016 12:01:02 GMT+0800
week, dd month yyyy HH:mm:ss GMT±HHmm

前者默認當前時區時間,後者可以設置時區

標準格式

直到 ES5.1 15.9.1.15 Date Time String Format 才有了日期字符串的格式標準:

// 0 區時間
YYYY-MM-DDTHH:mm:ss.sssZ
// 東邊時間
YYYY-MM-DDTHH:mm:ss.sss+HH:mm
// 西邊時間
YYYY-MM-DDTHH:mm:ss.sss-HH:mm

這份規範是 2011 年 6 月的,所以兼容性可想而知,樣子比較奇怪,但恪守標準的 Safari 是支持的,例如:

// 0 區時間
// Sat Oct 01 2016 20:01:02 GMT+0800 (CST)
new Date('2016-10-01T12:01:02Z')
// 東 8 區時間
// Sat Oct 01 2016 12:01:02 GMT+0800 (CST)
new Date('2016-10-01T12:01:02+08:00')

同樣的,0 區時間還是會被私自加上時區偏移,那麼很容易想到這兩個:

new Date('2016-10-01T12:01:02+00:00')
new Date('2016-10-01T12:01:02-00:00')

它們全都等價於 Z,同樣會被本地化偏移

三。GMT 與 UTC

一般可以認為這兩個東西是相同的,都表示世界標準時間,而北京位於東八區,那麼:

// 一般可以認為
北京時間 === UTC+8 === GMT+8

UTC 與 GMT 在時區的概念上一致,但 UTC 強調精確,誤差更小,這個誤差是相對 UT 來說的

GMT

GMT(Greenwich Mean Time 格林威治標準時間)是最早定義的世界時間。1884 年,各國代表跑去華盛頓開會,對時區達成共識,以本初子午線為中心(位於 0 區),向東 1 到 11 區,向西 1 到 11 區,共用 12 區(叫「東西 12 區」),一共24 個時區

由 0 區發布標準時間,然後其它區加上對應的偏移量得到本地時間

UT

UT(Universal Time 世界時)是基於天體觀察計算出來的時間。UT 本身是一個廣泛的概念,其下包括 UT0,UT1,UT2 等。其中 UT0 是完全按照天體運行計算出來的時間,UT1 是在 UT0 的基礎上做了一些調整,UT2 是在 UT0 和 UT1 的基礎上又進行了一些調整。由於天體運行的一些不確定性 (比如地球的自轉並非勻速的,而是以複雜的方式進行著加速和減速),所以 UT 時間並不是均勻流過的。

UT 就是理論上的「正確」時間

UTC

UTC(Universal Time Coordinate 協調世界時)是基於原子時鐘的時間。什麼是原子時鐘?個人認為就是一個很小的,長度固定的,不可再分的時間段。所以 UTC 的時間是均勻的。為了能夠盡量減小和 UT 時間的誤差,UTC 引入了閏秒(在某些年份的最後一分鐘是 61 秒),以確保 UTC 是 UT1 之間的誤差在 0.9 秒之內。

UTC 認同 GMT 的時區概念,所以 UTC 相當於給 GMT 換了塊更高級的表,GMT 用的什麼表就不知道了

四。潛在問題

與北京時間相差最多的是西 12 區(只有幾個小島):

deltaH = (+8) - (-12) = 20

如果做了一個本地時間判斷,比如:

if (new Date() > new Date('2016/10/02')) {
    alert('a new day');
}

那麼不同時區的用戶都將在手頭的設備顯示 2016 年 10 月 2 日 0 點 0 分非 0 毫秒時看到 a new day,這沒問題,但如果場景是這樣:

if (new Date() > new Date('2016/10/02')) {
    alert('考試時間到,3 秒後回到首頁');
    setTimeout(function() {
        location.href = '/index.html';
    }, 3000);
}

此時問題就大了,北京時間 2016 年 10 月 2 日 0 點 0 分非 0 毫秒,試卷狀態變更為 CLOSED,不再接受提交,那麼位於其它時區的用戶就發現問題了:

  • 住在西 12 區的朋友還有 20 個小時慢慢答題,交卷時發現人家不要

  • 住在東 12 區的朋友更慘,被提前 4 小時收卷了

當然,我們一般都是進頁面先問服務要狀態,以服務器時間為準,因為本地時間不可靠(用戶可以隨便修改設備時間),另一個原因就是上面提到的:時區的差異會讓位於其它時區的用戶很困惑

所以,即便非要用本地時間判斷,也應該這樣做:

if (new Date() > new Date('02 October, 2016 GMT+0800')) {
    alert('考試時間到,3 秒後回到首頁');
    setTimeout(function() {
        location.href = '/index.html';
    }, 3000);
}

拿用戶本地時間與北京時間比,至少在用戶設備時間的情況下,能保證狀態一致。當然,手動改時間的問題是沒有辦法避免的(比如以前的某些農場遊戲用的是本地時間),所以盡量不要把本地時間作為判斷依據

五。總結

本地時間是指設備所在時區時間

兼容性最好的時間串格式:

// 不支持時區
2016/10/01 12:01:02
yyyy/MM/dd HH:mm:ss
// 支持時區
new Date('01 October, 2016 GMT+0800')
week, dd month yyyy HH:mm:ss GMT±HHmm

ES5.1 標準時間串格式:

2016-10-01T12:01:02+08:00
YYYY-MM-DDTHH:mm:ss.sss±HH:mm

千萬不要用的時間串格式:

// 兼容性沒問題,但會被強制偏移,比如設備在北京就 +8 小時
yyyy-MM-dd
// Safari 全家都不支持,IE6-11 都不支持
yyyy-MM-dd HH:mm:ss

參考資料

評論

暫無評論,快來發表你的看法吧

提交評論