你可能不知道的 Date 類

xcold發表於2019-02-16

Date 是 JS 中的重要的一個內建物件,其例項主要用於處理時間和日期,其時間基於 1970-1-1 (世界標準時間)起的毫秒數,時間戳長度為 13 位(不同於 Unix 時間戳的長度 10 位)。對於日期和時間,我們有無數個使用場景,因此需要特別注意一些細節和約定。

1. 建構函式

通過 new Date() 可以進行例項化,得到一個 Date 物件例項,值得注意的是如果直接執行 Date() ,將得到一個時間字串。

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

<!– more –>

其中對建構函式的引數說明(參考 MDN ):

  • 如果沒有輸入任何引數,則Date的構造器會依據系統設定的當前時間來建立一個Date物件。
  • 如果提供了至少兩個引數,其餘的引數均會預設設定為1(如果沒有提供day引數)或者0。
  • JavaScript的時間是由世界標準時間(UTC)1970年1月1日開始,用毫秒計時,一天由86,400,000毫秒組成。Date物件的範圍是-100,000,000天至100,000,000天(等效的毫秒值)。
  • JavaScript的Date物件為跨平臺提供了統一的行為。時間屬性可以在不同的系統中表示相同的時刻,而如果使用了本地時間物件,則反映當地的時間。
  • JavaScript 的Date物件提供了數個UTC時間的方法,也相應提供了當地時間的方法。UTC,也就是我們所說的格林威治時間,指的是time中的世界時間標準。而當地時間則是指執行JavaScript的客戶端電腦所設定的時間。
  • 以一個函式的形式來呼叫JavaScript的Date物件(i.e., 不使用 new 操作符)會返回一個代表當前日期和時間的字串。

2. 空值處理

// 以chrome為例
new Date();
// Mon Oct 23 2017 23:38:02 GMT+0800 (CST)

new Date(false);
// Thu Jan 01 1970 08:00:00 GMT+0800 (CST)

new Date(0);
// Thu Jan 01 1970 08:00:00 GMT+0800 (CST)

new Date(null);
// Thu Jan 01 1970 08:00:00 GMT+0800 (CST)

new Date(``);
// Invalid Date

new Date(undefined);
// Invalid Date

3. 特別提示

[Firefox]

不支援帶 `-` 的完整時間,比如 new Date(`2012-07-08 00:00:00`) 為無效的值,而 new Date(`2012-07-08`) 是正確的值。

[month]

  • new Date(year, month, ……) 中的month從0開始計算

4. 值的邊界

不同執行環境下的邊界值有差異, Chrome 下甚至連負值都能支援。在實際生產環境中,不僅需要考慮時間的展示,還需要考慮其儲存、計算等,因此在特定的場景下,我們需要儘可能考慮到資料庫和瀏覽器中 Date 的有效範圍。

以資料庫 Derby 儲存時間為例,其邊界為:

說明 邊界值
最小的日期 0001-01-01
最大的日期 9999-12-31
最小的時間 00:00:00
最大的時間 24:00:00
最小的時間戳 0001-01-01-00.00.00.000000
最大的時間戳 9999-12-31-23.59.59.999999

mysql 中,其範圍定義為 1000-01-01to9999-12-31
js 中,時間戳的最小值為 -8640000000000000 即公元前 271,821 年 4 月 20 日,最大值為 8640000000000000,即 275,760 年 9 月 13 日。規範中時間範圍為 1970/1/1 前後 100,000,000 天。

5. 2038 年蟲

聽說,2038 年之後時間戳不夠用了。

在計算機應用上,2038年問題可能會導致某些軟體在2038年無法正常工作。所有使用UNIX時間表示時間的程式都將受其影響,因為它們以自1970年1月1日經過的秒數(忽略閏秒)來表示時間。這種時間表示法在類Unix(Unix-like)作業系統上是一個標準,並會影響以其C程式語言開發給其他大部份作業系統使用的軟體。在大部份的32位作業系統上,此“time_t”資料模式使用一個有正負號的32位元整數(signedint32)儲存計算的秒數。依照此“time_t”標準,在此格式能被表示的最後時間是2038年1月19日03:14:07,星期二(UTC)。超過此一瞬間,時間將會被掩蓋(wrap around)且在內部被表示為一個負數,並造成程式無法工作,因為它們無法將此時間識別為2038年,而可能會依個別實作而跳回1970年或1901年。錯誤的計算及動作可能因此產生。

實際上參考第 4 部分,Date 的上限綽綽有餘,大家可以拿起手頭的裝置測試一下 2038 年會出現怎樣的異狀。

6. 參考

1、EmacScript 語言規範 – http://ecma-international.org/ecma-262/5.1/#sec-15.9
2、Mysql 時間範圍 – https://dev.mysql.com/doc/refman/5.5/en/datetime.html
3、JS 時間戳邊界 – https://stackoverflow.com/questions/11526504/minimum-and-maximum-date

7. 庫

  • moment – 重量級時間處理庫,支援時間解析、格式化、計算等,功能強大,支援瀏覽器和 Node.js,壓縮後體積約為 16.3 KB
  • date-fns – 較 moment 更輕量級的事件處理庫,體積更小
  • dayjs – 更輕量級的 moment.js

相關文章