轉載自:http://web.jobbole.com/89120/javascript
本部分的知識圖譜請參考編程語言知識圖譜-時間與日期。
css
本文JavaScript 時間與日期處理實戰:你確定被坑過從屬於筆者的Web 前端入門與最佳實踐中 JavaScript 入門與最佳實踐系列文章。html
GMT即「格林威治標準時間」(Greenwich Mean Time,簡稱G.M.T.),指位於英國倫敦郊區的皇家格林威治天文臺的標準時間,由於本初子午線被定義爲經過那裏的經線。然而因爲地球的不規則自轉,致使GMT時間有偏差,所以目前已不被看成標準時間使用。UTC是最主要的世界時間標準,是通過平均太陽時(以格林威治時間GMT爲準)、地軸運動修正後的新時標以及以「秒」爲單位的國際原子時所綜合精算而成的時間。UTC比GMT來得更加精準。其偏差值必須保持在0.9秒之內,若大於0.9秒則由位於巴黎的國際地球自轉事務中央局發佈閏秒,使UTC與地球自轉週期一致。不過平常使用中,GMT與UTC的功能與精確度是沒有差異的。協調世界時區會使用「Z」來表示。而在航空上,全部使用的時間劃一規定是協調世界時。並且Z在無線電中應讀做「Zulu」(可參見北約音標字母),協調世界時也會被稱爲「Zulu time」。前端
人們常常會把時區與UTC偏移量搞混,UTC偏移量表明瞭某個具體的時間值與UTC時間之間的差別,一般用HH:mm形式表述。而TimeZone則表示某個地理區域,某個TimeZone中每每會包含多個偏移量,而多個時區可能在一年的某些時間有相同的偏移量。譬如America/Chicago, America/Denver, 以及 America/Belize在一年中不一樣的時間都會包含 -06:00 這個偏移。java
Unix時間戳表示當前時間到1970年1月1日00:00:00 UTC對應的秒數。注意,JavaScript內的時間戳指的是當前時間到1970年1月1日00:00:00 UTC對應的毫秒數,和unix時間戳不是一個概念,後者表示秒數,差了1000倍。git
1
2
|
YYYY
/
MM
/
DD
HH
:
MM
:
SS
±
timezone
(時區用
4位數字表示
)
// eg 1992/02/12 12:23:22+0800
|
國際標準化組織的國際標準ISO 8601是日期和時間的表示方法,全稱爲《數據存儲和交換形式·信息交換·日期和時間的表示方法》。目前最新爲第三版ISO8601:2004,初版爲ISO8601:1988,第二版爲ISO8601:2000。年由4位數組成,以公曆公元1年爲0001年,以公元前1年爲0000年,公元前2年爲-0001年,其餘以此類推。應用其餘紀年法要換算成公曆,但若是發送和接受信息的雙方有共同一致贊成的其餘紀年法,能夠自行應用。github
1
2
3
4
5
6
|
YYYY
-
MM
-
DDThh
:
mm
:
ss
±
timezone
(時區用
HH
:
MM表示
)
1997
-
07
-
16T08
:
20
:
30Z
// 「Z」表示UTC標準時區,即"00:00",因此這裏表示零時區的`1997年7月16日08時20分30秒`
//轉換成位於東八區的北京時間則爲`1997年7月17日16時20分30秒`
1997
-
07
-
16T19
:
20
:
30
+
01
:
00
// 表示東一區的1997年7月16日19時20秒30分,轉換成UTC標準時間的話是1997-07-16T18:20:30Z
|
JavaScript爲咱們提供了不是很好用的Date對象做爲時間日期對象,Date()直接返回當前時間字符串,無論參數是number仍是任何string。而new Date()則是會根據參數來返回對應的值,無參數的時候,返回當前時間的字符串形式;有參數的時候返回參數所對應時間的字符串。new Date()對參數不論是格式仍是內容都要求,且只返回字符串,標準的構造Date對象的方法有:web
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// 不帶new操做符,像一個函數同樣調用。它將忽略全部傳入的參數,並返回當前日期和時間的一個字符串表示。
new
Date
(
)
;
// 可接受一個數字參數,該參數表示設定時間與1970年1月1日0點之間的毫秒數。
new
Date
(
value
)
;
// 可接受一個字符串參數,參數形式相似於Date.parse()方法。但parse()方法返回的是一個數字,而Date()函數返回的是一個對象。
new
Date
(
dateString
)
;
// 可接受參數形式相似於Date.UTC()方法的參數,但Date.UTC()方法返回是一個毫秒數,且是UTC時間,而Date()函數返回是一個對象,且是本地時間。
new
Date
(
year
,
month
[
,
day
[
,
hour
[
,
minutes
[
,
seconds
[
,
milliseconds
]
]
]
]
]
)
;
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
-
year:四位年份,若是寫成兩位數,則加上
1900
month:表示月份,
0表示一月,
11表示
12月
date:表示日期,
1到
31
hour:表示小時,
0到
23
minute:表示分鐘,
0到
59
second:表示秒鐘,
0到
59
ms:表示毫秒,
0到
999
|
這裏須要注意的是,月份month參數,其計數方式從0開始,而天day參數,其計數方式從1開始。chrome
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
new
Date
(
)
;
//Fri Aug 21 2015 15:51:55 GMT+0800 (中國標準時間)
new
Date
(
1293879600000
)
;
new
Date
(
'2011-01-01T11:00:00'
)
new
Date
(
'2011/01/01 11:00:00'
)
new
Date
(
2011
,
0
,
1
,
11
,
0
,
0
)
new
Date
(
'jan 01 2011,11 11:00:00'
)
new
Date
(
'Sat Jan 01 2011 11:00:00'
)
//Sat Jan 01 2011 11:00:00 GMT+0800 (中國標準時間)
new
Date
(
'sss'
)
;
new
Date
(
'2011/01/01T11:00:00'
)
;
new
Date
(
'2011-01-01-11:00:00'
)
new
Date
(
'1293879600000'
)
;
//Invalid Date
new
Date
(
'2011-01-01T11:00:00'
)
-
new
Date
(
'1992/02/11 12:00:12'
)
//596069988000
|
若是須要從當前的時間對象獲取其相應的時間戳,咱們可使用getTime或者valueOf(),返回距離1970年1月1日0點的毫秒數:npm
1
2
3
4
5
6
7
8
|
var
date1
=
new
Date
(
2007
,
0
,
1
)
;
var
date2
=
new
Date
(
2007
,
1
,
1
)
;
console
.
log
(
date1
>
date2
)
;
//false
console
.
log
(
date1
<
date2
)
;
//true
// ECMAScript5新增了now()方法,該方法返回當前時間距離1970年1月1日0點UTC的毫秒數。該方法不支持傳遞參數
Date
.
now
=
function
(
)
{
return
(
new
Date
(
)
)
.
getTime
(
)
}
|
另外Date對象還有一個靜態方法一樣返回給定日期的毫秒數。但其參數並非一個字符串,而是分別表明年、月、日、時、分、秒、毫秒的數字參數:
1
2
3
4
5
6
|
console
.
log
(
Date
.
UTC
(
1970
)
)
;
//NaN
console
.
log
(
Date
.
UTC
(
1970
,
0
)
)
;
//0
console
.
log
(
Date
.
UTC
(
1970
,
0
,
2
)
)
;
//86400000
console
.
log
(
Date
.
UTC
(
1970
,
0
,
1
,
1
)
)
;
//3600000
console
.
log
(
Date
.
UTC
(
1970
,
0
,
1
,
1
,
59
)
)
;
//714000
console
.
log
(
Date
.
UTC
(
1970
,
0
,
1
,
1
,
59
,
30
)
)
;
//717000
|
仍是須要強調下,JavaScript內的時間戳指的是當前時間到1970年1月1日00:00:00 UTC對應的毫秒數,和unix時間戳不是一個概念,後者表示秒數,差了1000倍。new Date(timestamp)
中的時間戳必須是number
格式,string
會返回Invalid Date
。因此好比new Date('11111111')
這種寫法是錯的。
JavaScript原生Date對於時間字符串的解析真的是槽點滿滿,假設咱們但願以DD/MM/YYYY的格式進行解析,那麼它是沒法識別的:
1
2
|
var
a
=
new
Date
(
'01/12/2016'
)
;
//December 1 2016 in DD/MM/YYYY format
//"Tue Jan 12 2016 00:00:00 GMT-0600 (Central Standard Time)"
|
另外,在ES5的標準中,其對ISO 8601標準的字符串進行了一個神奇的斷言:全部沒有提供時區的字符串默認爲標準時區。換言之,你會發現你解析出來的時間和你預期中的不同,並且它打印的時候是按照本地時區又進行了轉換:
1
2
3
4
5
6
7
|
//US local format
var
a
=
new
Date
(
'1/1/2016'
)
;
//"Fri Jan 01 2016 00:00:00 GMT-0600 (Central Standard Time)"
//ISO 8601
var
a
=
new
Date
(
'2016-01-01'
)
;
//"Thu Dec 31 2015 18:00:00 GMT-0600 (Central Standard Time)"
|
ES 2015標準中則是修復了該Bug,不過仍是會讓人以爲頭大,畢竟你不知道你代碼的最終運行環境會是ES5仍是ES6。Date對象也有一個parse方法,用於解析一個日期字符串,參數是一個包含待解析的日期和時間的字符串,返回從1970年1月1日0點到給定日期的毫秒數。該方法會根據日期時間字符串格式規則來解析字符串的格式,除了標準格式外,如下格式也支持。若是字符串沒法識別,將返回NaN。
1
2
3
4
5
6
7
|
console
.
log
(
Date
.
parse
(
'6/13/2004'
)
)
;
//1087056000000
console
.
log
(
Date
.
parse
(
'January 12,2004'
)
)
;
//1073836800000
console
.
log
(
Date
.
parse
(
'Tue May 25 2004 00:00:00 GMT-0700'
)
)
;
//1085468400000
console
.
log
(
Date
.
parse
(
'2004-05-25T00:00:00'
)
)
;
//1085443200000
console
.
log
(
Date
.
parse
(
'2016'
)
)
;
//1451606400000
console
.
log
(
Date
.
parse
(
'T00:00:00'
)
)
;
//NaN
console
.
log
(
Date
.
parse
(
)
)
;
//NaN
|
在ECMAScript5中,若是使用標準的日期時間字符串格式規則的字符串中,數學前有前置0,則會解析爲UTC時間,時間沒有前置0,則會解析爲本地時間。其餘狀況通常都會解析爲本地時間
1
2
3
|
console
.
log
(
Date
.
parse
(
'7/12/2016'
)
)
;
//1468252800000
console
.
log
(
Date
.
parse
(
'2016-7-12'
)
)
;
//1468252800000
console
.
log
(
Date
.
parse
(
'2016-07-12'
)
)
;
//1468281600000
|
Date對象提供了一系列get*方法,用來獲取實例對象某個方面的值。具體的Get函數列表詳見附錄:
1
2
3
4
5
6
7
|
var
d
=
new
Date
(
'January 6, 2013'
)
;
d
.
getDate
(
)
// 6
d
.
getMonth
(
)
// 0
d
.
getYear
(
)
// 113
d
.
getFullYear
(
)
// 2013
d
.
getTimezoneOffset
(
)
// -480
|
一樣的,Date對象還提供了一系列的Set方法:
1
2
3
4
5
6
7
8
9
|
var
d1
=
new
Date
(
'January 6, 2013'
)
;
d1
.
setDate
(
32
)
// 1359648000000
d1
// Fri Feb 01 2013 00:00:00 GMT+0800 (CST)
var
d2
=
new
Date
(
'January 6, 2013'
)
;
d
.
setDate
(
-
1
)
// 1356796800000
d
// Sun Dec 30 2012 00:00:00 GMT+0800 (CST)
|
咱們能夠巧用Set方法的特性,set*方法的參數都會自動折算。以setDate爲例,若是參數超過當月的最大天數,則向下一個月順延,若是參數是負數,表示從上個月的最後一天開始減去的天數。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
var
d1
=
new
Date
(
'January 6, 2013'
)
;
d1
.
setDate
(
32
)
// 1359648000000
d1
// Fri Feb 01 2013 00:00:00 GMT+0800 (CST)
var
d2
=
new
Date
(
'January 6, 2013'
)
;
d
.
setDate
(
-
1
)
// 1356796800000
d
// Sun Dec 30 2012 00:00:00 GMT+0800 (CST)
var
d
=
new
Date
(
)
;
// 將日期向後推1000天
d
.
setDate
(
d
.
getDate
(
)
+
1000
)
;
// 將時間設爲6小時後
d
.
setHours
(
d
.
getHours
(
)
+
6
)
;
// 將年份設爲去年
d
.
setFullYear
(
d
.
getFullYear
(
)
-
1
)
;
|
類型轉換時,Date對象的實例若是轉爲數值,則等於對應的毫秒數;若是轉爲字符串,則等於對應的日期字符串。因此,兩個日期對象進行減法運算,返回的就是它們間隔的毫秒數;進行加法運算,返回的就是鏈接後的兩個字符串。
1
2
3
4
5
6
7
8
|
var
d1
=
new
Date
(
2000
,
2
,
1
)
;
var
d2
=
new
Date
(
2000
,
3
,
1
)
;
d2
-
d1
// 2678400000
d2
+
d1
// "Sat Apr 01 2000 00:00:00 GMT+0800 (CST)Wed Mar 01 2000 00:00:00 GMT+0800 (CST)"
|
Date對象提供了一系列的to*
方法來支持從Date對象轉化爲字符串,具體的函數列表詳見附錄:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
var
d
=
new
Date
(
2013
,
0
,
1
)
;
d
.
toString
(
)
// "Tue Jan 01 2013 00:00:00 GMT+0800 (CST)"
d
.
toUTCString
(
)
// "Mon, 31 Dec 2012 16:00:00 GMT"
d
.
toISOString
(
)
// "2012-12-31T16:00:00.000Z"
d
.
toJSON
(
)
// "2012-12-31T16:00:00.000Z"
d
.
toDateString
(
)
// "Tue Jan 01 2013"
d
.
toTimeString
(
)
// "00:00:00 GMT+0800 (CST)"
d
.
toLocaleDateString
(
)
// 中文版瀏覽器爲"2013年1月1日"
// 英文版瀏覽器爲"1/1/2013"
d
.
toLocaleTimeString
(
)
// 中文版瀏覽器爲"上午12:00:00"
// 英文版瀏覽器爲"12:00:00 AM"
|
1
2
3
4
5
|
const
nMS
=
1320
;
//以毫秒單位表示的差值時間
var
nD
=
Math
.
floor
(
nMS
/
(
1000
*
60
*
60
*
24
)
)
;
var
nH
=
Math
.
floor
(
nMS
/
(
1000
*
60
*
60
)
)
%
24
;
var
nM
=
Math
.
floor
(
nMS
/
(
1000
*
60
)
)
%
60
;
var
nS
=
Math
.
floor
(
nMS
/
1000
)
%
60
;
|
瀏覽器獲取當前用戶所在的時區等信息只和系統的日期和時間設置裏的時區以及時間有關。區域和語言設置影響的是瀏覽器默認時間函數(Date.prototype.toLocaleString等)顯示的格式,不會對時區等有影響。Date有個Date.prototype.toLocaleString()方法能夠將時間字符串返回用戶本地字符串格式,這個方法還有兩個子方法Date.prototype.toLocaleDateString和Date.prototype.toLocaleTimeString,這兩個方法返回值分別表示日期和時間,加一塊兒就是Date.prototype.toLocaleString的結果。這個方法的默認參數會對時間字符串作一次轉換,將其轉換成用戶當前所在時區的時間,並按照對應的系統設置時間格式返回字符串結果。然而不一樣瀏覽器對用戶本地所使用的語言格式的判斷依據是不一樣的。
1
2
3
4
5
6
7
8
9
10
|
window
.
navigator
.
language
//"nl-NL"
window
.
navigator
.
systemLanguage
//"zh-CN"(設置中的非unicode程序所使用語言選項)
window
.
navigator
.
userLanguage
//"nl-NL"
window
.
navigator
.
browserLanguage
//"ja-JP"(系統菜單界面語言)
window
.
navigator
.
languages
//undefined
|
1
2
3
4
5
6
7
8
9
|
window
.
navigator
.
language
//'en-US'
window
.
navigator
.
languages
//["en-US", "zh-CN", "de", "zh", "en"]
//當界面語言改成"en-US",`accept-language`首位爲`zh-CN`的時候
window
.
navigator
.
language
//'zh-CN'(`accept-language`首選值)
window
.
navigator
.
languages
//["zh-CN", "de", "zh", "en-US", "en"]
|
1
2
3
4
5
6
7
|
window
.
navigator
.
language
//'zh-CN'
window
.
navigator
.
languages
//["en-US", "en", "zh-CN", "zh", "ja", "zh-TW", "de-LI", "de", "pl"]
//當界面語言改成"en-US"時
window
.
navigator
.
language
//'en-US'(瀏覽器界面語言)
|
Moment.js爲JavaScript Date對象提供了封裝與統一好的API接口,而且提供了更多的功能。首先須要瞭解的是,Moment提供的moment對象是可變的,即當咱們對該對象執行相似於增減或者設置的時候,其對象自己的值會發生變化,譬以下面這段代碼:
1
2
3
4
|
var
a
=
moment
(
'2016-01-01'
)
;
var
b
=
a
.
add
(
1
,
'week'
)
;
a
.
format
(
)
;
"2016-01-08T00:00:00-06:00"
|
而若是咱們不但願改變原有的值,特別是在須要建立多個時間日期對象的時候,咱們能夠利用clone方法:
1
2
3
4
|
var
a
=
moment
(
'2016-01-01'
)
;
var
b
=
a
.
clone
(
)
.
add
(
1
,
'week'
)
;
a
.
format
(
)
;
"2016-01-01T00:00:00-06:00"
|
筆者是習慣在Webpack中進行打包,相似於Node下的安裝方式:
1
2
3
4
5
|
//安裝
npm
install
moment
//使用
var
moment
=
require
(
'moment'
)
;
moment
(
)
.
format
(
)
;
|
若是你須要引入某個語言包,那麼能夠用以下方式:
1
2
3
|
var
moment
=
require
(
'moment'
)
;
require
(
'moment/locale/cs'
)
;
console
.
log
(
moment
.
locale
(
)
)
;
// cs
|
1
2
3
4
|
//毫秒
var
day
=
moment
(
1318781876406
)
;
//秒
var
day
=
moment
.
unix
(
1318781876
)
;
|
1
2
3
4
5
6
7
|
moment
(
"2010-10-20 4:30"
,
"YYYY-MM-DD HH:mm"
)
;
// parsed as 4:30 local time
moment
(
"2010-10-20 4:30 +0000"
,
"YYYY-MM-DD HH:mm Z"
)
;
// parsed as 4:30 UTC
moment
(
"2010 13"
,
"YYYY MM"
)
.
isValid
(
)
;
// false (not a real month)
moment
(
"2010 11 31"
,
"YYYY MM DD"
)
.
isValid
(
)
;
// false (not a real day)
moment
(
"2010 2 29"
,
"YYYY MM DD"
)
.
isValid
(
)
;
// false (not a leap year)
moment
(
"2010 notamonth 29"
,
"YYYY MMM DD"
)
.
isValid
(
)
;
// false (not a real month name)
|
1
2
3
4
5
6
7
8
9
10
|
moment
(
)
.
seconds
(
30
)
===
new
Date
(
)
.
setSeconds
(
30
)
;
moment
(
)
.
seconds
(
)
===
new
Date
(
)
.
getSeconds
(
)
;
moment
(
)
.
get
(
'year'
)
;
moment
(
)
.
get
(
'month'
)
;
// 0 to 11
moment
(
)
.
get
(
'date'
)
;
moment
(
)
.
get
(
'hour'
)
;
moment
(
)
.
get
(
'minute'
)
;
moment
(
)
.
get
(
'second'
)
;
moment
(
)
.
get
(
'millisecond'
)
;
|
1
2
3
4
5
6
7
8
9
|
moment
(
)
.
set
(
'year'
,
2013
)
;
moment
(
)
.
set
(
'month'
,
3
)
;
// April
moment
(
)
.
set
(
'date'
,
1
)
;
moment
(
)
.
set
(
'hour'
,
13
)
;
moment
(
)
.
set
(
'minute'
,
20
)
;
moment
(
)
.
set
(
'second'
,
30
)
;
moment
(
)
.
set
(
'millisecond'
,
123
)
;
moment
(
)
.
set
(
{
'year'
:
2013
,
'month'
:
3
}
)
;
|
1
2
3
4
5
6
7
8
9
10
11
|
moment
(
)
.
add
(
Number
,
String
)
;
moment
(
)
.
add
(
Duration
)
;
moment
(
)
.
add
(
Object
)
;
moment
(
)
.
add
(
7
,
'days'
)
;
moment
(
)
.
subtract
(
Number
,
String
)
;
moment
(
)
.
subtract
(
Duration
)
;
moment
(
)
.
subtract
(
Object
)
;
moment
(
)
.
subtract
(
7
,
'days'
)
;
|
1
2
3
4
5
|
moment
(
)
.
isBefore
(
Moment
|
String
|
Number
|
Date
|
Array
)
;
moment
(
)
.
isBefore
(
Moment
|
String
|
Number
|
Date
|
Array
,
String
)
;
moment
(
'2010-10-20'
)
.
isBefore
(
'2010-12-31'
,
'year'
)
;
// false
moment
(
'2010-10-20'
)
.
isBefore
(
'2011-01-01'
,
'year'
)
;
// true
|
1
2
3
4
5
6
7
|
moment
(
)
.
diff
(
Moment
|
String
|
Number
|
Date
|
Array
)
;
moment
(
)
.
diff
(
Moment
|
String
|
Number
|
Date
|
Array
,
String
)
;
moment
(
)
.
diff
(
Moment
|
String
|
Number
|
Date
|
Array
,
String
,
Boolean
)
;
var
a
=
moment
(
[
2007
,
0
,
29
]
)
;
var
b
=
moment
(
[
2007
,
0
,
28
]
)
;
a
.
diff
(
b
,
'days'
)
// 1
|
1
2
3
4
|
moment
(
)
.
format
(
)
;
// "2014-09-08T08:02:17-05:00" (ISO 8601)
moment
(
)
.
format
(
"dddd, MMMM Do YYYY, h:mm:ss a"
)
;
// "Sunday, February 14th 2010, 3:25:50 pm"
moment
(
)
.
format
(
"ddd, hA"
)
;
// "Sun, 3PM"
moment
(
'gibberish'
)
.
format
(
'YYYY MM DD'
)
;
// "Invalid date"
|
1
2
|
moment
(
[
2007
,
0
,
29
]
)
.
fromNow
(
)
;
// 4 years ago
moment
(
[
2007
,
0
,
29
]
)
.
fromNow
(
true
)
;
// 4 years
|
1
2
3
|
moment
.
duration
(
1
,
"minutes"
)
.
humanize
(
)
;
// a minute
moment
.
duration
(
2
,
"minutes"
)
.
humanize
(
)
;
// 2 minutes
moment
.
duration
(
24
,
"hours"
)
.
humanize
(
)
;
// a day
|
Date 對象用於處理日期和時間。其核心的方法以下列表所示:
方法 | 描述 |
---|---|
Date() | 返回當日的日期和時間。 |
getDate() | 從 Date 對象返回一個月中的某一天 (1 ~ 31)。 |