JavaScript中的Date對象

這篇文章的目的主要是講解JavaScript中的Date對象,同時解答下面幾個困惑我好久的問題:html

  • 能夠解析的表示時間的字符串格式有哪些?
  • 時區TimeZone
  • 進位問題

名詞約定

表示時間的詞不少,好比時間日期時刻等,爲了便於下面的講解以及概念的統一,對於下面這種格式瀏覽器

YYYY-MM-DDTHH:mm:ss.sssZ

如今統一約定:函數

  • YYYY-MM-DD: 也就是年月日部分使用日期這個詞;
  • HH:mm:ss.sss: 也就是時分秒部分使用時刻這個詞;
  • YYYY-MM-DDTHH:mm:ss.sssZ: 也就是說並不特指日期時刻時,咱們用時間這個詞;

其它名詞約定:prototype

  • 時間對象:經過Date構造函數建立的對象;
  • 內部插槽:指官網文檔中的internal slot
  • 計算機時區:指計算機設置的時區,而不是計算機所在地區的時區;

雖然JavaScript用了Date這個單詞,這個單詞翻譯過來是日期,可是從上面的約定來看,翻譯成時間這個詞或許更爲合適。翻譯

至於爲何採用上面這種字符串格式,而不是YYYY/MM/DD HH:mm:ss或者其它格式進行說明的緣由下面會說起。code

另外,下面全部代碼的運行環境爲Chrome瀏覽器,而且註釋部分不必定表明返回值。orm

內容結構

文章將會從如下幾個方面進行講解:htm

  • Date概述
  • Date做爲構造器的用法;
  • Date做爲函數的用法;
  • Date上的靜態方法;
  • getter相關函數;
  • setter相關函數;

Date概述

經過把Date做爲構造函數使用,能夠建立一個時間對象,這個時間對象表示時間長河中的一個時間點。時間對象內部有一個名爲[[DateValue]]的內部插槽,這個內部插槽裏面存儲的是一個時間戳。這個時間戳表示的是以世界協調時的1970年1月1日0時0分0秒0毫秒做爲起始的毫秒數。對象

問:不知道是否有人有過疑問,時間戳和時區相關嗎,同一時間不一樣時區獲取的時間戳同樣嗎?
答:根據上面時間戳的規定,時間戳就是從世界協調時開始算的,因此能夠說時間戳和時區有關,這個時區就是世界協調時。但也是由於這個時區是定死的,因此不一樣的時區在同一時間獲取到的時間戳都是同樣的。ip

Date做爲構造器的用法

JavaScript中,咱們常常會經過參數的類型和個數讓函數做出不一樣的處理,如:

function justForExample () { // 這個例子只是起說明做用,並沒有實際意義
    let length = arguments.length
    if (length === 0) return 'zero parameter'
    if (length === 1) return arguments[0]
    if (length === 2) return arguments[0] + arguments[1] // 兩個參數作加法
    if (length === 3) return arguments[0] * arguments[1] * arguments[2] // 三個參數作乘法
    // ...
}

Date也是經過判斷參數的類型和個數來進行不一樣處理的。Date能夠處理的參數的個數是07個。

當參數的個數是0的時候,返回一個時間對象,[[DateValue]]內部插槽的值表明以世界協調時爲基準的當前時間的時間戳。

當參數的個數是1的時候,還需根據參數的類型作進一步判斷:

  1. 若是參數的類型是數字,返回一個時間對象,[[DateValue]]內部插槽的值就是這個數字,固然若是這個數據不合法或者超出邊界的話,這個插槽的值就不必定是這個數字了。未免本文過於囉嗦,本文不討論數字不合法或者超出邊界等其它狀況,有興趣的能夠參閱規範文檔。
  2. 若是參數的類型是字符串,就會調用Date上的靜態方法parse,而後把返回值做爲[[DateValue]]的值。具體詳見下面的Date.parse

當參數的個數大於2的時候,就會使用下面這種形式:

// 從左到右參數分別表明年,月,日,時,分,秒,毫秒
Date (year, month [,date [, hours [, minutes [, seconds [, ms ]]]]])

上面這種形式接受27個參數。日的默認值是1,時,分,秒,毫秒的默認值是0

須要注意的是:

  1. 月份是從0開始算的,也就是0表明1月1表明2月...11表明12月
  2. 我在文章的開始說過一個進位的問題。咱們知道當兩個十進制的數相加時,若是低位超出該位的最大值,那麼就會向高位進位,以使該位的值在合法範圍以內。一樣,在Date構造器以上述形式調用的時候,就會發生自動進位,也就是若是該位的值已經超出了該位的最大值,並不會報錯,而是自動執行進位操做:

    // 進位
    new Date(2018, 8, 34) // Thu Oct 04 2018 00:00:00 GMT+0800 (中國標準時間)
    // 退位,相似於數學中的減法,也是能夠的
    new Date(2018, 8, -1) // Thu Aug 30 2018 00:00:00 GMT+0800 (中國標準時間)

    能夠看到,第三個參數34表示月份中的天數,可是9月只有30天,因此34並非9月合法的日期,因此就產生了進位,月份進入10月,而後日期是4日,也就是34-30。同理,當第三個參數是-1的時候,會退到8月份。

  3. 時區是計算機時區。也就是年,月,日,時,分,秒,毫秒錶明的是計算機時區的時間。所以,不一樣的計算機返回的時間多是不同的:

    let date1 = new Date(2018, 8, 8, 8, 8, 8) // Sat Sep 08 2018 08:08:08 GMT+0800 (中國標準時間)
    date1.getTime() // 1536365288000
    
    // 而後,改了下計算機時區
    let date2 = new Date(2018, 8, 8, 8, 8, 8) // Sat Sep 08 2018 08:08:08 GMT+0300 (莫斯科標準時間)
    date2.getTime() // 1536383288000
    
    (date1 - date2) / 3600 / 1000 // 5,由於date1是東八區,date2是東三區,正好相差5個小時

Date做爲函數的用法

Date做爲普通函數調用時,並不會對參數進行處理,直接返回表明當前時間的字符串。

Date() // "Sat Aug 18 2018 17:26:16 GMT+0800 (中國標準時間)"
Date(2018, 9, 9) // "Sat Aug 18 2018 17:26:21 GMT+0800 (中國標準時間)"

Date上的靜態方法

Date上的靜態方法有三個:

  • Date.now()
  • Date.parse(string)
  • Date.UTC(year, month [, date [, hours [, minutes [, seconds [, ms ]]]]])

Date.now()

返回函數調用時,以世界協調時爲基準的時間戳。

Date.parse(string)

Date.parse處理第一個參數,返回一個以世界協調時爲基準的時間戳。
在上面介紹Date做爲構造函數使用的時候,當參數的個數是1,而且類型是字符串時,會在內部調用Date.parse方法。
咱們平時見過不少表示時間的格式:

"2018-08-08 08:08:08"
"2018/08/08 08:08:08"
"2018/8/8 8:8:8"
...

那麼,JavaScript支持的格式有哪些?JavaScript是否支持上述所有格式呢?

根據文檔,規範只定義了一種格式:YYYY-MM-DDTHH:mm:ss.sssZ,其中T表明時間的開始,Z表明時區,也就是世界協調時。時區還能夠用或者-拼上HH:mm來表示。這也是我爲何在開頭使用這種格式的緣由。當字符串的格式不符合上述格式的時候,就交給具體的實現本身看着辦了。

須要注意的是:

  1. 儘可能使用規範規定的字符串格式,不然可能會出現不一樣的瀏覽器運行結果不一致的問題;
  2. 另外上述格式不是全部部分都有才算合法,能夠省略某些部分,日期部分容許的格式以下:

    YYYY
    YYYY-MM
    YYYY-MM-DD

    時刻部分容許的格式以下:

    THH:mm
    THH:mm:ss
    THH:mm:ss.sss

    能夠只使用上面的日期格式,也可使用上面的任意一種日期格式+上面的任意一種時刻格式。月、日的默認值是"01",時、分、秒的默認值是"00",毫秒的默認值是"000"。時區缺省的時候,日期+時刻的格式表明的是計算機時區。

    // 只有日期格式
    new Date('2018-08-08') // Wed Aug 08 2018 08:00:00 GMT+0800 (中國標準時間)
    // 日期+時刻格式,時區默認是計算機時區
    new Date('2018-08-08 08:08:08') // Wed Aug 08 2018 08:08:08 GMT+0800 (中國標準時間)
    // 時區爲東三區,個人電腦是在東八區,因此輸出的時間是08+05,也就是13點
    new Date('2018-08-08 08:08:08+03:00') // Wed Aug 08 2018 13:08:08 GMT+0800 (中國標準時間)

    上面第一個例子,能夠發現當只有日期格式的時候,字符串是按照世界協調時解析的,也就是世界協調時的2018年8月8日,因此東八區就變成了8點了。文檔只規定了日期+時刻格式默認時區是計算機時區,只有日期的時候並無規定用什麼時區,因此儘可能不要用日期格式。
    因此,就我的而言,我以爲應該儘可能避免使用字符串格式來實例化一個時間對象。當想建立一個本地時區的時間對象時,可使用上面Date做爲構造函數接受27個參數的那種形式去實例化一個時間對象。

  3. 沒有進位問題,相應部分超出合法值以外就會報錯:

    new Date('2018-08-34') // Invalid Date

Date.UTC(year, month [, date [, hours [, minutes [, seconds [, ms ]]]]])

相似於上面Date做爲構造函數時,使用27個參數的形式。不一樣之處在於:

  1. 依據的時區不一樣,該方法參考世界協調時,而不是計算機時區;
  2. 返回值不一樣,該方法返回以世界協調時爲基準的時間戳,而不是一個時間對象。

因此,能夠經過下述方式建立參數以計算機時區和世界協調時爲基準的時間對象:

// 參數是以計算機時區爲基準
new Date(2018, 8, 8) // Sat Sep 08 2018 00:00:00 GMT+0800 (中國標準時間)
// 參數是以世界協調時爲基準
new Date(Date.UTC(2018, 8, 8)) // Sat Sep 08 2018 08:00:00 GMT+0800 (中國標準時間)

getter相關函數

獲取一個時間對象的年、月、日、時、分、秒、毫秒等都有對應的方法,這裏再也不贅述,只簡述幾個注意點:

  1. 上述方法針對計算機時區和世界協調時都有對應的一系列方法,如獲取小時:

    // Date.prototype.getHours() 計算機時區
    // Date.prototype.getUTCHours() 世界協調時
    let date = new Date(2018, 8, 8, 8) //Sat Sep 08 2018 08:00:00 GMT+0800 (中國標準時間)
    date.getHours() // 8
    date.getUTCHours() // 0
  2. Date.prototype.getTime()返回時間對象的內部插槽[[DateValue]]的值,也就是以世界協調時爲基準的時間戳。

setter相關函數

getter相關函數同樣,設置一個時間對象的年、月、日、時、分、秒、毫秒等都有對應的方法,這裏一樣再也不贅述。只簡述幾個注意點:

  1. getter相關函數同樣,上述方法針對計算機時區和世界協調時都有對應的一系列方法,如設置日期:

    // Date.prototype.setHours() 計算機時區
    // Date.prototype.setUTCHours() 世界協調時
    let date = new Date(2018, 8, 8, 8) //Sat Sep 08 2018 08:00:00 GMT+0800 (中國標準時間)
    date.setHours(9) // Sat Sep 08 2018 09:00:00 GMT+0800 (中國標準時間)
    date.setUTCHours(9) // Sat Sep 08 2018 17:00:00 GMT+0800 (中國標準時間)
  2. 設置月、日、時、分、秒、毫秒的時候,一樣會有進位:

    let date = new Date(2018, 8, 8) // Sat Sep 08 2018 00:00:00 GMT+0800 (中國標準時間)
    
    date.setDate(34) // Thu Oct 04 2018 00:00:00 GMT+0800 (中國標準時間)

總結

但願上述內容對你們有所幫助。若是發現本文有什麼錯誤,您能夠在評論區留言。

相關文章
相關標籤/搜索