[譯] JAVASCRIPT 日期權威指南

CoderMing發表於2018-09-14

在 JavaScript 中使用日期是很複雜的。請試著學習所有特性並學會如何使用它。

引言

在工作中使用日期是非常複雜的。無論開發人員的技術如何,都會感受到相當痛苦。

JavaScript 通過一個強大的 Date 內建物件來提供處理日期的功能。

這篇文章不會討論 Moment.js 這個我認為是處理日期的最好的庫,你應該在絕大多數場景下用它來處理日期。

Date 物件

一個 Date 物件例項描述一個單一的時間點。

儘管其被命名為 Date,但其也操縱著 具體的時間(譯者注:意為其也可以描述時分秒)。

初始化一個 Date 物件

我們通過以下方式初始化一個 Date 物件:

new Date()
複製程式碼

這將會創造一個指向當前時刻的 Date 物件。

從內部來看,Date 物件是表示距離 1970 年 1 月 1 日(UTC)所過去的毫秒數。這一天(1970 年 1 月 1 日)是非常重要的,因為就計算機而言,這是一切開始的地方。

你可能比較熟悉 UNIX 時間戳:它表示距離眾人皆知的那天(1970 年 1 月 1 日)所過去的秒數。

要點:UNIX 時間戳的結果是“秒”,JavaScript 的 Date 物件的結果是“毫秒”。

如果我們有一個 UNIX 時間戳,我們可以通過下面的方法類比出一個 JavaScript Date 物件:

const timestamp = 1530826365
new Date(timestamp * 1000)
複製程式碼

如果我們傳值為 0,我們將會得到一個表示 1970年1月1日的 JavaScript Date 物件:

new Date(0)
複製程式碼

如果我們傳值一個字串而不是數字,那麼Date物件將會呼叫 parse 去確定你想傳入的日期。例如:

new Date('2018-07-22')
new Date('2018-07') //July 1st 2018, 00:00:00
new Date('2018') //Jan 1st 2018, 00:00:00
new Date('07/22/2018')
new Date('2018/07/22')
new Date('2018/7/22')
new Date('July 22, 2018')
new Date('July 22, 2018 07:22:13')
new Date('2018-07-22 07:22:13')
new Date('2018-07-22T07:22:13')
new Date('25 March 2018')
new Date('25 Mar 2018')
new Date('25 March, 2018')
new Date('March 25, 2018')
new Date('March 25 2018')
new Date('March 2018') //Mar 1st 2018, 00:00:00
new Date('2018 March') //Mar 1st 2018, 00:00:00
new Date('2018 MARCH') //Mar 1st 2018, 00:00:00
new Date('2018 march') //Mar 1st 2018, 00:00:00
複製程式碼

這個方法非常靈活。你可以在月份或者日期欄位新增或省略前導零。

小心月份/日期的位置,不然你或許會將月份錯看成是日期。

你也可以使用 Date.parse 方法:

Date.parse('2018-07-22')
Date.parse('2018-07') //July 1st 2018, 00:00:00(譯者注:此處的結果為一個時間戳數字,該數字代表 July 1st 2018, 00:00:00 時刻)
Date.parse('2018') //Jan 1st 2018, 00:00:00(譯者注:意思同上)
Date.parse('07/22/2018')
Date.parse('2018/07/22')
Date.parse('2018/7/22')
Date.parse('July 22, 2018')
Date.parse('July 22, 2018 07:22:13')
Date.parse('2018-07-22 07:22:13')
Date.parse('2018-07-22T07:22:13')
複製程式碼

Date.parse 方法將會返回一個時間戳(以毫秒計)而不是 Date 物件。

你也可以通過設定一串有序的表示以一個日期的各個部分的數值來建立一個 Date 物件:年份,月份(從 0 開始),日期,小時,分鐘,秒數和毫秒數:

new Date(2018, 6, 22, 7, 22, 13, 0)
new Date(2018, 6, 22)
複製程式碼

這個方法最少需要三個引數,但是大多數 JavaScript 引擎也可以解析更少引數的情況:

new Date(2018, 6) //Sun Jul 01 2018 00:00:00 GMT+0200 (Central European Summer Time)
new Date(2018) //Thu Jan 01 1970 01:00:02 GMT+0100 (Central European Standard Time)
複製程式碼

在上述所用的情況下,所生成的 Date 都是與你現在所在的時區相關聯的。這意味著 兩個不同的電腦可能將同一個 Date 物件例項解釋成不同的值。

JavaScript 在沒有找到任何關於時區的資訊時,會把時區設定成 UTC,同時也會自動地(對非當前時區的 Date 物件)進行到當前計算機時區的轉換。

總結一下,你可以通過四種方式來建立一個 Date 物件:

  • 不傳任何引數 ,這將建立一個指向“當前時刻”的 Date 物件
  • 傳遞 一個數字,該引數將表示建立的 Date 物件距離 1970 年 1 月 1 日 00:00(GMT)所過去的毫秒數
  • 傳遞 一個字串,該字串應該是一個描述日期的字串
  • 傳遞 一串引數,這些引數會分別描述一個 Date 物件的某一部分

時區

當你初始化一個 Date 物件時可以選擇時區,這樣做的話 Date 物件不會是預設的 UTC 時區,同時也會覆蓋你所在的時區。

你可以通過新增 +HOURS 的格式,或者通過一個被圓括號包裹的時區名來描述一個時區:

new Date('July 22, 2018 07:22:13 +0700')
new Date('July 22, 2018 07:22:13 (CET)')
複製程式碼

如果你使用時區名的方式但在圓括號中定義了一個錯誤的時區名,JavaScript 將會靜默地將時區設定為預設的 UTC。

如果你使用 +HOURS 的方式但傳入的數字格式是錯誤的,JavaScript 將會丟擲一個 “Invalid Date” 的 Error。

Date 轉換及格式化

給定一個 Date 物件,會有許多種可以生成與該時間相關的字串的方式。

const date = new Date('July 22, 2018 07:22:13')

date.toString() // "Sun Jul 22 2018 07:22:13 GMT+0200 (Central European Summer Time)"
date.toTimeString() //"07:22:13 GMT+0200 (Central European Summer Time)"
date.toUTCString() //"Sun, 22 Jul 2018 05:22:13 GMT"
date.toDateString() //"Sun Jul 22 2018"
date.toISOString() //"2018-07-22T05:22:13.000Z" (ISO 8601 format)
date.toLocaleString() //"22/07/2018, 07:22:13"
date.toLocaleTimeString()	//"07:22:13"
date.getTime() //1532236933000
date.getTime() //1532236933000
複製程式碼

Date 物件的 get(獲取)方法

一個 Date 物件會提供如下方法去檢視它的值。這些值會取決於你計算機所處的時區。

const date = new Date('July 22, 2018 07:22:13')

date.getDate() //22
date.getDay() //0(0 表示週日,1 表示週一...)
date.getFullYear() //2018
date.getMonth() //6(從 0 開始計)
date.getHours() //7
date.getMinutes() //22
date.getSeconds() //13
date.getMilliseconds() //0(未標明)(譯者注:此處的意思為 Date 物件建立時指定毫秒值,JavaScript 預設將毫秒數設定為 0)
date.getTime() //1532236933000
date.getTimezoneOffset() //-120(將會取決於你在哪和你檢視的時間 — 例子中的值表示在 CET 時區的夏天)。返回以分鐘表示的時間差(譯者注:此處涉及到協調世界時及夏令時)
複製程式碼

這兒還有一些相似的使用 UTC 時區的方法,它們會使用 UTC 時區而不是你所在的時區。

date.getUTCDate() //22
date.getUTCDay() //0(0 表示週日,1 表示週一...)
date.getUTCFullYear() //2018
date.getUTCMonth() //6(從 0 開始計)
date.getUTCHours() //5(看吧,不是上面的結果“7”)
date.getUTCMinutes() //22
date.getUTCSeconds() //13
date.getUTCMilliseconds() //0(未標明)
複製程式碼

修改 Date

一個 Date 物件提供以下修改 Date 值的方法:

const date = new Date('July 22, 2018 07:22:13')

date.setDate(newValue)
date.setDay(newValue)
date.setFullYear(newValue) //note:不要使用 setYear(),它已經被廢棄了
date.setMonth(newValue)
date.setHours(newValue)
date.setMinutes(newValue)
date.setSeconds(newValue)
date.setMilliseconds(newValue)
date.setTime(newValue)
date.setTimezoneOffset(newValue)
複製程式碼

setDaysetMonth 的取值範圍從 0 開始,舉個例子,三月的值為 2。

一個有趣的事實是:這些方法是互相重合的,舉個例子,如果你執行 date.setHours(48),這也會將日期數變大。

很棒的知識點:你可以對 setHours() 新增超過一個引數來設定分鐘,秒鐘和毫秒:setHours(0, 0, 0, 0) ——這也適用於 setMinutessetSeconds。(譯者注:即 setMinutes 可以設定分鐘,秒和毫秒,setSeconds 可以設定秒和毫秒)

和 get(獲取)方法一樣,set(修改)方法也有相同的 UTC 版本:

const date = new Date('July 22, 2018 07:22:13')

date.setUTCDate(newalue)
date.setUTCDay(newValue)
date.setUTCFullYear(newValue)
date.setUTCMonth(newValue)
date.setUTCHours(newValue)
date.setUTCMinutes(newValue)
date.setUTCSeconds(newValue)
date.setUTCMilliseconds(newValue)
複製程式碼

獲取正確的時間戳

如果你想獲得以毫秒計的時間戳,你可以使用如下簡寫:

Date.now()
複製程式碼

下面這種方式更加複雜:

new Date().getTime()
複製程式碼

JavaScript 費盡心思讓程式碼工作正常

請注意。如果你定義的日期天數超過了一個月,這將不會報錯,同時 Date 物件將會指向下一個月:

new Date(2018, 6, 40) //Thu Aug 09 2018 00:00:00 GMT+0200 (Central European Summer Time)
複製程式碼

這對月份,小時,分鐘,秒鐘,毫秒同樣有效。

基於你的地點來格式化 Date

全球化的API,在現代化的瀏覽器中被很好地支援(值得注意的例外:UC 瀏覽器),而這允許你去轉化(世界各地的)日期。

這些方法由 Intl 專案公佈,它同時也幫助我們本地化數字,字串和貨幣。

我們對 Intl.DateTimeFormat() 非常有興趣。

這裡說的是如何使用它:

按照電腦所在地區來格式化一個 Date 物件:

// "12/22/2017"
const date = new Date('July 22, 2018 07:22:13')
new Intl.DateTimeFormat().format(date) //"22/07/2018" 是我所在地區的格式
複製程式碼

按照不同地區來格式化一個 Date 物件:

new Intl.DateTimeFormat('en-US').format(date) //"7/22/2018"
複製程式碼

Intl.DateTimeFormat 方法有一個可選的引數可以去自定義輸出。下面是同時展示小時,分鐘和秒數的方法:

const options = {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
}

new Intl.DateTimeFormat('en-US', options).format(date) //"7/22/2018, 7:22:13 AM"
new Intl.DateTimeFormat('it-IT', options2).format(date) //"22/7/2018, 07:22:13"
複製程式碼

這裡是你可用引數的參考

對比兩個 Date

你可以通過 Date.getTime() 的值來比較兩個 Date 物件:

const date1 = new Date('July 10, 2018 07:22:13')
const date2 = new Date('July 22, 2018 07:22:13')
const diff = date2.getTime() - date1.getTime() //以毫秒計的差距
複製程式碼

同樣的方法,你也可以去檢查兩個 Date 物件是否相等:

const date1 = new Date('July 10, 2018 07:22:13')
const date2 = new Date('July 10, 2018 07:22:13')
if (date2.getTime() === date1.getTime()) {
  // 它們相等時所執行的程式碼
}
複製程式碼

謹記,getTime() 方法返回以毫秒計的數字,所以你需要將當日時刻計入對照之中。July 10, 2018 07:22:13 不等於 July 10, 2018。在這種情況下,你可以使用 setHours(0, 0, 0, 0) 來重置當日時刻。

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。

掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄


相關文章