平時對 Date
很多內容都一知半解,每次一用到 Date
就需要查資料,著實惱火。
故此文記錄關于 JavaScript 日期操作那些我不知道的事。
基礎問題
Date.prototype.getTime() 返回的數字是什么?
官方對 getTime()
函數對定義是
The getTime() method returns the number of milliseconds* since the Unix Epoch
getTime()
函數返回從 unix 時間戳(Unix Epoch) 開始到當前 Date
所指時間經過的毫秒數。
unix 時間戳 又代表什么呢?
1970年1月1日00:00:00(UTC/GMT的午夜)
所以 getTime()
返回的數字是從 1970年1月1日0時0分0秒開始到當前 Date
對象所指時間所經過的毫秒數。
例如:
getTime()
和你所在的時區也有關系,我國的標準時間是北京時間,在東八區,所以比英國格林威治時間(GMT)的 0 時區晚 8 個小時。所以我定義的 1970年1月1日使用 getTime
函數得到 -2880000,即 8 小時。
GMT 和 UTC 是什么,有什么區別?
GMT(格林尼治標準時間) 和 UTC(協調世界時) 是計算世界時間的兩種標準。
GMT 根據地球的自轉和公轉來計算時間,也就是太陽每天經過位于英國倫敦郊區的皇家格林威治天文臺的時間就是中午12點。UTC是根據原子鐘來計算時間,目前世界上最精確的原子鐘50億年才會誤差1秒。因為地球的自傳正在緩速變慢,會導致 GMT 計算有誤差,所以 UTC 比 GMT 更加精確。UTC 時間被認為能與 GMT 時間互換,但 GMT 因為天文觀測本身的缺陷,已經漸漸被 UTC 所取代。
PS:兩個都是 0 時區的時間,例如:UTC +8 = 北京時間。
Date.getMonth() 為什么要從 0 開始
誰能想到這是 Java 埋的坑,因為 Javascript 的 Date
實現方案是 JDK1.0 的方案,所以坑也一樣。
Javascript 之父用一句
Make It Look Like Java
調侃了這個坑也告訴了我們答案。
問題來了,Java 獲取月份為什么要從 0 開始呢?
- 說法 1: 可能是因為舊的 C 語言日期 API 是這樣的,那么舊的 C 語言日期 API 為什么是這樣呢?...不套娃了。
- 說法 2:計算機里面所有東西都從 0 開始
- 說法 3:從 0 開始做月份計算更加容易
例如 12 月的下一個月份是 1 月,不過為了計算出 1 月你會做以下計算:
12 + 1 = 13 // 13 月是哪個月?
我們可以用 12 取余快速修復上面的問題
(12 + 1) % 12 = 1
但是當遇到 11 月的時候...
(11 + 1) % 12 = 0 // 0 月是哪個月?
您可以在添加月份之前先減去1,然后再進行取余運算,最后再加1,就可以修復上面的問題...也可以解決這個“基本問題”。
((11 - 1 + 1) % 12) + 1 = 12 // 許多神奇的數字!
現在我們來看看如果月份的數字是 0 - 11,會有什么問題?
(0 + 1) % 12 = 1 // February
(1 + 1) % 12 = 2 // March
(2 + 1) % 12 = 3 // April
(3 + 1) % 12 = 4 // May
(4 + 1) % 12 = 5 // June
(5 + 1) % 12 = 6 // July
(6 + 1) % 12 = 7 // August
(7 + 1) % 12 = 8 // September
(8 + 1) % 12 = 9 // October
(9 + 1) % 12 = 10 // November
(10 + 1) % 12 = 11 // December
(11 + 1) % 12 = 0 // January
所有月份的表現一致,無需較復雜的解決方案。
時間戳是什么?
常指 unix 時間戳,上文提到過:從1970年1月1日(UTC/GMT的午夜)開始所經過的秒數。
獲取時間戳的代碼:
Math.round(new Date().getTime()/1000)
常用方法
定義時間的方法
傳入時間格式的字符串
new Date('September 11, 1995 03:24:00')
new Date('1995-09-11T03:24:00')
new Date('Mon Sep 11 1995')
不同的瀏覽器實現有差異,強烈不建議使用字符串初始化/解析日期。建議使用傳入數字初始化日期對象。相同的瀏覽器針對不同的定義方式也有些許差異。
例子1:
new Date(Date.parse("Jul 8, 2005"));//Fri Jul 08 2005 00:00:00 GMT+0800 (China Standard Time)
new Date(Date.parse("2005-07-08"));//Fri Jul 08 2005 08:00:00 GMT+0800 (China Standard Time)
例子2:在 2020年以前的,Firefox 和 Chrome 針對以下代碼實現有差異。
Date.parse('1970-01-01T00:00:00Z'); // Chrome: 0 FF: 0
Date.parse('1970-01-01T00:00:00-0500'); // Chrome:18000000 FF: 18000000
Date.parse('1970-01-01T00:00:00'); // Chrome: 0 FF: -28800000
傳入多個時間單位的數字
new Date(1995, 8, 11)//注意,月份需要減 1,例如定義 9 月,第二個月份參數需要傳 8
new Date(1995, 8, 11, 3, 24, 0)
傳入 Unix 時間戳
new Date(810761040000) //Mon Sep 11 1995 03:24:00 GMT+0800 (China Standard Time)
時間的加減法
減法
首先,需要將你的日期轉化為 Date 對象,然后直接使用加減符號計算差。得到的結果是和或差的毫秒數,再將毫秒轉化成你需要的格式。例如 2020-01-01 和 2020-01-02 差多久?
new Date(2020,0,2)-new Date(2020,0,1)//86400000[ms]
如果結果是要計算差多少天,即是 86400000 除以 1000得到秒數,再除以 60 得到分鐘數,以此類推。
86400000/1000/60/60/24 //1
加法
兩個 Date
相減能得到毫秒,那理所當然地某個 Date
加上毫秒數就可以等于另一個日期了。例如 2020-01-01 加上 86400000 毫秒,就等于 2020-01-02。
No!No!No!
new Date(2020,0,1)+86400000
//Wed Jan 01 2020 00:00:00 GMT+0800 (China Standard Time)86400000
我還是太年輕了,跨類型的兩個對象,強行加在一起,不甜。
1.轉換成數字相加
將 new Date(2020,0,1)
轉換成毫秒,來到整形的世界,快樂地計算。
(new Date(2020,0,1).getTime()+86400000)
//Thu Jan 02 2020 00:00:00 GMT+0800 (China Standard Time)
2.使用 JS 內置方法
加減年、月、日、時、分、秒。例如:
var date=new Date(2020,0,1);
date.setDate(date.getDate()+1)
//date:Thu Jan 02 2020 00:00:00 GMT+0800 (China Standard Time)
不同的時間單位的加法使用的方法不同,可以根據下表選擇對應的方法。
單位 | 獲取時間 | 設置時間 | 例子 |
---|---|---|---|
秒 | getSeconds | setSeconds | date.setSeconds(date.getSeconds()+1) |
分 | getMinutes | setMinutes | date.setMinutes(date.getMinutes()+1) |
時 | getHours | setHours | date.setHours(date.getHours()+1) |
日 | getDate | setDate | date.setDate(date.getDate()+1) |
周 | setFullYear | getFullYear | date.setFullYear(date.getFullYear() + x) |
月 | getMonth | setMonth | date.setMonth(date.getMonth()+1) |
年 | setFullYear | getFullYear | date.setFullYear(date.getFullYear() + x) |
比較時間的大小
獲取毫秒數,進行數字大小的比較。
new Date(2020,0,1).getTime()>=new Date(2020,0,1).getTime() //true
獲取不同格式的當前時間
toString()
new Date().toString();
//Fri Sep 18 2020 00:18:59 GMT+0800 (China Standard Time)"
toLocaleString()
new Date().toLocaleString();
// 9/18/2020, 12:18:16 AM
toUTCString()/toGMTString()
new Date().toUTCString();
new Date().toGMTString();
//Thu, 17 Sep 2020 16:10:04 GMT
GMT 已經不被推薦使用了,原因在上文提到過:UTC 比 GMT 精確。
toISOString()
new Date().toISOString();
//2020-09-17T16:20:06.419Z
返回 ISO
格式 (ISO 8601)的日期。
ISO
格式日期的規則是生成格式為 YYYY-MM-DDTHH:mm:ss.sssZ 或者 ±YYYYYY-MM-DDTHH:mm:ss.sssZ 的24 位到 27 位字符串。
YYYY-MM-DDTHH:mm:ss.sssZ 里面的 T 是分隔日期和時間的符號。
YYYY-MM-DDTHH:mm:ss.sssZ 里面的 Z 是時區的占位符,可以不寫時區用 Z 代替是 0 時區,也可以使用 2020-09-17T00:20:06+08:00 代表東八區。