新聞中心
Date背景
眾所周知,在 1995 年,Brendan(JavaScript之父) 被網(wǎng)景公司安排了一個(gè)巨大而緊急的工作任務(wù),用 10 天的時(shí)間來(lái)編寫 JavaScript 語(yǔ)言。而 日期處理 是幾乎所有編程語(yǔ)言的基本部分,所以JavaScript 也必須擁有它。

創(chuàng)新互聯(lián)專業(yè)做網(wǎng)站、成都做網(wǎng)站,集網(wǎng)站策劃、網(wǎng)站設(shè)計(jì)、網(wǎng)站制作于一體,網(wǎng)站seo、網(wǎng)站優(yōu)化、網(wǎng)站營(yíng)銷、軟文推廣等專業(yè)人才根據(jù)搜索規(guī)律編程設(shè)計(jì),讓網(wǎng)站在運(yùn)行后,在搜索中有好的表現(xiàn),專業(yè)設(shè)計(jì)制作為您帶來(lái)效益的網(wǎng)站!讓網(wǎng)站建設(shè)為您創(chuàng)造效益。
這是一個(gè)非常復(fù)雜的領(lǐng)域,但留給作者編寫它的時(shí)間卻很短。最終 Brendan 選擇了借鑒當(dāng)時(shí)紅極一時(shí)的 java 語(yǔ)言,從java.Util.Date日期實(shí)現(xiàn)中復(fù)制了 Javascript 的日期對(duì)象。坦率地說(shuō),這個(gè)實(shí)現(xiàn)很糟糕。事實(shí)上 Java 在兩年后的 1.1 版本中就棄用和替換這種實(shí)現(xiàn)。然而 20 年后,我們?nèi)匀辉?JavaScript 編程語(yǔ)言中使用這個(gè) API。
Date存在的問(wèn)題
- 不支持除用戶本地時(shí)間以外的時(shí)區(qū)
不支持開發(fā)人員通過(guò) API 來(lái)切換時(shí)區(qū)信息。
- 解析器行為不可靠以至于無(wú)法使用
new Date();
new Date(value);
new Date(dateString);
new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);
開發(fā)人員常常因?yàn)檩斎氲膮?shù)格式問(wèn)題,引發(fā)時(shí)間錯(cuò)誤,導(dǎo)致程序崩潰。比如輸入 ('2022-02-22') 和 (2022,02,22) 得到的結(jié)果卻不同,
- 計(jì)算 API 缺失
涉及時(shí)間的運(yùn)算邏輯通常都需要開發(fā)人員自己去寫,比如比較兩個(gè)時(shí)間的長(zhǎng)短,時(shí)間之間的加減運(yùn)算,沒(méi)有自己的計(jì)算API
- 不支持非公歷
除了全球通用的公歷外,無(wú)法使用各國(guó)的自己的歷法。比如中國(guó)的農(nóng)歷
Temporal的誕生
為了彌補(bǔ) Date 的缺陷,很多程序員著手開發(fā)一些開源的庫(kù)來(lái)繞過(guò)對(duì) Date 的直接使用,比較優(yōu)秀的npm庫(kù)如 date.js 、moment.js,但 Date 的問(wèn)題始終困擾著 Javascript 這門語(yǔ)言的進(jìn)一步發(fā)展,于是 TC39 組織開始了對(duì) Date 的升級(jí)改造,他們找到了 moment.js 庫(kù)的作者,Maggie ,由她來(lái)?yè)?dān)任新特性 Temporal的主力設(shè)計(jì)。
感興趣的同學(xué)可以去博客[1]閱讀更多細(xì)節(jié),該網(wǎng)頁(yè)的控制臺(tái)已經(jīng)支持Temporal 對(duì)象或者在本地運(yùn)行,安裝Temporal的 polyfill
$ npm install @js-temporal/polyfill
import { Temporal} from '@js-temporal/polyfill';
Temporal是一個(gè)全局對(duì)象,像 Math 、Promise 一樣位于頂級(jí)命名空間中,為 Javascript 語(yǔ)言帶來(lái)了現(xiàn)代化的日期、時(shí)間接口。
如圖所示,一個(gè)全面的Temporal包含三個(gè)部分:
綠色區(qū)域?yàn)?ISO 8601 格式的 日期和時(shí)間;
黃色區(qū)域?yàn)闀r(shí)區(qū)(日本東京);
紅色區(qū)域?yàn)槿諝v(日本歷法);
ISO 8601格式:國(guó)際通用時(shí)間格式,T用來(lái)分割日期(2020-08-05)和時(shí)間(20:06:13),“+”或者“-”分別代表東時(shí)區(qū)和西時(shí)區(qū)。+09:00,代表東九區(qū)。
對(duì)比 Date
new Date()
//Fri Jan 28 2022 17:03:11 GMT+0800 (中國(guó)標(biāo)準(zhǔn)時(shí)間)
Date 采用 GMT格式(舊的時(shí)間表示格式) 的時(shí)間,使用方面不如 ISO 8601 通用,同時(shí)不包含 時(shí)區(qū)和歷法。
Temporal各種類型介紹
推翻重新設(shè)計(jì)的Temporal,包含5種主要 類型,每個(gè)類型負(fù)責(zé)不同的功能,類型之間還可以相互進(jìn)行轉(zhuǎn)換。
學(xué)會(huì)了這5種類型的 功能 以及類型的之間的 關(guān)系 ,就基本掌握了Temporal。
下面是Temporal各種類型的功能與轉(zhuǎn)換關(guān)系圖,非常重要,十分有利于我們?nèi)胬斫夂褪褂肨emporal,下文將逐步講解。
ZonedDateTime
定義:最全面的Temporal類型,與時(shí)區(qū)和日歷都有關(guān)聯(lián)。表示從地球上特定區(qū)域的角度來(lái)看,在特定時(shí)刻發(fā)生的事。
使用場(chǎng)景:在北京時(shí)間的 2008年5月12日14時(shí)28分4秒發(fā)生汶川大地震,或者 在 紐約時(shí)間的 2008年5月12日01時(shí)28分4秒發(fā)生了汶川大地震。
如何獲得一個(gè) ZonedDateTime 類型?
不僅是獲得一個(gè) ZonedDateTime 類型,其實(shí)所有的 Temporal 類型都是一樣的獲取途徑。通常有兩種方法獲得,分別是 new 構(gòu)造函數(shù)(),和from方法。
- new 構(gòu)造函數(shù)()方式
參數(shù):(納秒數(shù),時(shí)區(qū),日歷),不同類型要求的參數(shù)不同。
納秒數(shù):從 Unix 紀(jì)元(1970 年 1 月 1 日午夜 UTC)計(jì)算,所經(jīng)過(guò)的納秒數(shù),單位為bigint
時(shí)區(qū),日期:可以是字符串,也可以是 Temporal 類型。
new Temporal.ZonedDateTime(0n, 'Asia/Shanghai', 'chinese');
//Temporal.ZonedDateTime <1970-01-01T08:00:00+08:00[Asia/Shanghai][u-ca=chinese]>
通常每個(gè)Temporal類型的都有toString()方法,覆蓋了Object.prototype.toString()方法,作用是通過(guò)一個(gè)字符串表示Temporal。
調(diào)用 toString() 用字符串來(lái)表達(dá),方便閱讀。
new Temporal.ZonedDateTime(0n, 'Asia/Shanghai', 'chinese').toString();
//1970-01-01T08:00:00+08:00[Asia/Shanghai][u-ca=chinese]
這個(gè) ZonedDateTime 的類型含義為,從北京時(shí)間看,unix紀(jì)元 起始時(shí)間為 1970-01-01T08:00:00+08:00,而非1970-01-01T00:00:00+00:00
- from()形式獲得一個(gè) Temporal 類型
from()的參數(shù)更為多樣,同時(shí)支持 溢出處理 (下文有講解),所以通常作為首選方法。通常作為獲得一個(gè) Temporal 類型的首選方法。
接受字符串
Temporal.ZonedDateTime.from('2022-02-28T00:00:00+08:00[Asia/Shanghai]').toString();
//2022-02-28T00:00:00+08:00[Asia/Shanghai]
or
接受對(duì)象,({時(shí)區(qū),日期,日歷},options)
options 代表 容錯(cuò)機(jī)制 配置,即可以處理輸入的日期溢出問(wèn)題,有兩種配置選項(xiàng),{ overflow: 'constrain' }:自動(dòng)處理溢出。{ overflow: 'reject' },日期溢出則報(bào)錯(cuò)。
比如下面例子中,2022年2月一共28天,如果選擇了 constrain 配置,輸入日期超過(guò)了會(huì)進(jìn)行溢出處理,即匹配最接近的存在值。
//輸入 31 天,得到 28 天
Temporal.ZonedDateTime.from({ timeZone: 'Asia/Shanghai', year: 2022, month: 2, day: 31}, { overflow: 'constrain' }).toString();
//2022-02-28T00:00:00+08:00[Asia/Shanghai]
選擇 reject 配置,日期超出則報(bào)錯(cuò)。
Temporal.ZonedDateTime.from({ timeZone: 'Asia/Shanghai', year: 2022, month: 2, day: 31}, { overflow: 'reject' }).toString();
//RangeError: value out of range: 1 <= 31 <= 28
Instant
定義:負(fù)責(zé)單個(gè)時(shí)間點(diǎn)(稱為 “精確時(shí)間” ),精度以納秒為單位。不存在時(shí)區(qū)和日歷信息。
使用場(chǎng)景:2020-01-23T17:04:36.491865121-08:00,只用來(lái)表達(dá)一個(gè)瞬間的時(shí)間,沒(méi)有其他意義。
獲得一個(gè) Instant 類型
new Temporal.Instant( bigint )
bigint:納秒數(shù),從 Unix 紀(jì)元(1970 年 1 月 1 日午夜 UTC)計(jì)算,所經(jīng)過(guò)的納秒數(shù),單位為bigint。
new Temporal.Instant(1553906700000000000n);
//2019-03-30T00:45:00Z
new Temporal.Instant(0n);
//1970-01-01T00:00:00Z
new Temporal.Instant(-2208988800000000000n);
//1900-01-01T00:00:00Z
Z 在 ISO 8601 時(shí)間格式表示,沒(méi)有時(shí)區(qū)關(guān)聯(lián)。
Temporal.Instant.from(thing: any)
from方法在生成 Instant 時(shí),會(huì)考慮時(shí)區(qū)的偏差。
Temporal.Instant.from('2019-03-30T01:45:00+01:00[Europe/Berlin]');
Temporal.Instant.from('2019-03-30T01:45+01:00');
Temporal.Instant.from('2019-03-30T00:45Z');
雖然前兩個(gè)攜帶了時(shí)區(qū)信息,但獲取到的Instant 時(shí)間值相同,三個(gè)都是 2019-03-30T00:45Z。
Plain XX系列
負(fù)責(zé) Temporal 的 日歷日期 (xx年xx月xx日) 和 鐘表時(shí)間 (xx點(diǎn)xx分xx秒)表達(dá),不涉及時(shí)區(qū),
使用場(chǎng)景:日歷日期:小紅的生日是農(nóng)歷 每年3月25。鐘表時(shí)間:現(xiàn)在是下午2:00
對(duì)比 Instant,雙方的 使用場(chǎng)景 不同, 內(nèi)部的屬性 也不同,Instant 不包含時(shí)區(qū)和日期,Plain XX 系列則包含日歷。
Plain XX系列包含 5種 類型,覆蓋最廣的 PlainDateTime 包含日期和時(shí)間,還有只包含日期的 Plaindate 和只包含時(shí)間的 Plaintime。日期類型里,還有分類更精細(xì)的PlainYearMonth(年月)和 PlainMonthDay(月天)
以 PlainDateTime 舉例,其他的類同。
獲取一個(gè) PlainDateTime
new Temporal.PlainDateTime(year,month,day...)
參數(shù)以 年 -> 納秒 順序排列,其中 年 月 日,為必填項(xiàng),其余選填。
new Temporal.PlainDateTime(2020, 3, 14, 13, 37)
//2020-03-14T13:37:00
Temporal.PlainDateTime.from()
Temporal.PlainDateTime.from({ year: 2001, month: 1, day: 1, hour: 25 ,calendar:'chinese'}, { overflow: 'constrain' }).toString()
//2001-01-24T23:00:00[u-ca=chinese]
TimeZone
定義:負(fù)責(zé) Temporal 時(shí)區(qū)的相關(guān)信息。
例子:北京時(shí)區(qū),東八區(qū),不單獨(dú)使用,通常結(jié)合其他類型搭配。
獲取一個(gè) TimeZone 類型
new Temporal.TimeZone(string)
string:對(duì)一個(gè)時(shí)區(qū)的描述
//東八區(qū),即北京時(shí)間
new Temporal.TimeZone('8:00');
//直接字符串描述,前提是 Temporal 內(nèi)部有定義
new Temporal.TimeZone('Asia/Shanghai');
//Asia/Shanghai
from同理
Temporal.TimeZone.from('Asia/Shanghai');
//Asia/Shanghai
在和其他類型搭配時(shí),可以直接使用字符串(“Asia/Shanghai”),或者 Temporal.TimeZone對(duì)象
例子:
獲取一個(gè) ZonedDateTime 類型,設(shè)置時(shí)區(qū)時(shí),使用 Temporal.TimeZone 對(duì)象。
new Temporal.ZonedDateTime(0n, Temporal.TimeZone.from('Asia/Shanghai'));
//1970-01-01T08:00:00+08:00[Asia/Shanghai]
等價(jià)于
new Temporal.ZonedDateTime(0n, 'Asia/Shanghai'));
Calendar
定義:負(fù)責(zé) Temporal 的日歷系統(tǒng)。
例子:中國(guó)農(nóng)歷。不單獨(dú)使用,結(jié)合其他類型搭配。
獲取一個(gè) Calendar 類型
同 TimeZone 類同,new Calendar(string) 或者 Temporal.Calendar.from(string)
new Temporal.Calendar('chinese').toString();
//chinese
Temporal.Calendar.from('chinese').toString();
//chinese
Calendar 類型不會(huì)單獨(dú)使用,要配合其他帶有 日歷屬性 的類型使用。
如上所述,在 Temporal 里,包含 日歷屬性 的有 plainXX系列 和 ZonedDateTime
這兩種類型的原型上有一個(gè) withCalendar的方法,用來(lái)設(shè)置該日期的日歷屬性。
例子:
plainXX系列 添加日歷屬性
沒(méi)有添加日歷屬性前
Temporal.PlainDate.from('2019-02-06');
//2019-02-06
添加日歷屬性后
Temporal.PlainDate.from('2019-02-06').withCalendar('chinese');
//2019-02-06[u-ca=chinese]
ZonedDateTime 添加日歷屬性
沒(méi)有添加日歷屬性前
Temporal.ZonedDateTime.from('2022-02-28T00:00:00+08:00[Asia/Shanghai]')
//2022-02-28T00:00:00+08:00[Asia/Shanghai]
添加日歷屬性后
Temporal.ZonedDateTime.from('2022-02-28T00:00:00+08:00[Asia/Shanghai]').withCalendar('chinese')
//2022-02-28T00:00:00+08:00[Asia/Shanghai][u-ca=chinese]
Duration
定義:表示一段持續(xù)時(shí)間,并且這段時(shí)間可以用來(lái)進(jìn)行 算術(shù)。
使用場(chǎng)景:兩段時(shí)間,一小時(shí)一分鐘 和 一小時(shí)十分鐘 ,可以轉(zhuǎn)換 Duration 類型,再進(jìn)行時(shí)間的長(zhǎng)度比較,從而得知前者的時(shí)長(zhǎng) 小于 后者。
Duration 并非像 Date 的 時(shí)間戳 形式那樣表達(dá)一段時(shí)間,而是根據(jù) ISO 8601 表示法生成一個(gè) 字符串 來(lái)表達(dá)一段時(shí)間。
簡(jiǎn)而言之,ISO 8601 表示法的首字母 必須 由 P 開頭,后跟日期,年、月、周和日 再由 T 字母進(jìn)行分割,后跟時(shí)間,小時(shí)、分鐘、 秒。
一個(gè) Duration 字符串可以缺失 年 / 月 / 周 / 日 / 小時(shí) / 分 / 秒 中的任意一個(gè),但必須包含首字母 P,如果同時(shí)有 小時(shí) / 分 / 秒,則必須包含字母 T。
舉例:
一年: P1Y,必須保留 P ,沒(méi)有時(shí)間信息,不用加 T來(lái)分割。
一分鐘: PT1M,必須保留 P ,有時(shí)間信息,則加 T來(lái)分割日期和時(shí)間
一些Duration 的字符串表達(dá)練習(xí)
獲得一個(gè) Duration 類型
new Temporal.Duration()
參數(shù):年 => 納秒,全部可選,非必填。需要按照順序輸入,某單位空缺則輸入 undefined 或者 0。
new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 654, 321);
// P1Y2M3W4DT5H6M7.987654321S
//中文翻譯 => 1年2月3周4天5小時(shí)6分鐘7秒987毫秒654微秒321納秒
new Temporal.Duration(0, 0, 0, 40);
// P40D 中文翻譯 => 40天
Temporal.Duration.from(undefined, undefined, undefined, 40);
// P40D
new Temporal.Duration();
// PT0S
了解了 Duration的字符串含義以及怎么生成一個(gè) Duration后,可以用其進(jìn)行一些 日期與時(shí)間 的計(jì)算與運(yùn)算。
比對(duì) 日期或時(shí)間 的長(zhǎng)度大小
調(diào)用 Duration 原型上的 compare 方法。返回值:-1, 0, 1
one = Temporal.Duration.from({ hours: 79, minutes: 10 });//PT1H10M
two = Temporal.Duration.from({ days: 3, hours: 7, seconds: 630 });//P3DT7H630S
Temporal.Duration.compare(one,two)
//-1
返回-1,則 one 比 two 的時(shí)間短
返回0,則 one 比 two 的時(shí)間一樣
返回-1,則 one 比 two 的時(shí)間長(zhǎng)
事實(shí)上,除了 Timezone 和 Calendar 類型外,所有具備日期和時(shí)間屬性的類型都可以進(jìn)行算術(shù)
如 PlainDateTime 類型:
one = Temporal.PlainDateTime.from('1995-12-07T03:24');
two = Temporal.PlainDateTime.from('1995-12-07T01:24');
Temporal.PlainDateTime.compare(two,two)
//1
日期或時(shí)間的 加減運(yùn)算。
加法:
Temporal.Duration.from('PT1H'); //PT1H
hour.add({ minutes: 30 });
// => PT1H30M
減法:
hourAndAHalf = Temporal.Duration.from('PT1H30M'); //PT1H30M
hourAndAHalf.subtract({ hours: 1 }); // => PT30M
同樣,這些算術(shù)除了除了 Timezone 和 Calendar 類型外,其他類型都適用。
如 PlainDateTime 類型:
dt = Temporal.PlainDateTime.from('1995-12-07T03:24:30.000003500');
dt.add({ years: 20, months: 4, nanoseconds: 500 });
// => 2016-04-07T03:24:30.000004
Temporal類型之間的轉(zhuǎn)換
Temporal的各種類型,除了完成自身的功能外,還可以 類型轉(zhuǎn)換。
再次回看這個(gè)類型關(guān)系圖,左側(cè)黃色區(qū)域的 Instant 類型,用來(lái)表達(dá)某個(gè)瞬間的時(shí)間,不包含時(shí)區(qū)和日歷的信息。
右側(cè)黃色區(qū)域的 PlainXX系列(5個(gè)),用來(lái)表達(dá)日歷日期或者鐘表時(shí)間,包含日歷信息,而中間的 ZonedDateTime 則橫跨左右兩個(gè)區(qū)域,包含時(shí)區(qū)和日歷信息,可以作為一個(gè)通道,連接左側(cè)的 Instant 和右側(cè)的 Plain系列,負(fù)責(zé)類型之間轉(zhuǎn)換的橋梁,同時(shí)中間的 Timezone 時(shí)區(qū)類型 Calendar 日歷類型,不單獨(dú)使用,配合上方的 ZonedDateTime 類型來(lái)輔助轉(zhuǎn)換。
最下面的 Duration 與所有類型沒(méi)有直接關(guān)系,不參與類型轉(zhuǎn)換,表示一段持續(xù)時(shí)間,并且這段時(shí)間可以用來(lái)進(jìn)行算術(shù)。
Instant => ZonedTimeDate
轉(zhuǎn)換前
Temporal.Instant.from('2020-08-05T20:06:13+0900').toString()
//2020-08-05T11:06:13Z
轉(zhuǎn)換后
Temporal.Instant.from('2020-08-05T20:06:13+0900').toZonedDateTimeISO('Asia/Tokyo').toString();
//2020-08-05T20:06:13+09:00[Asia/Tokyo]
ZonedTimeDate => Instant
轉(zhuǎn)換前
Temporal.ZonedDateTime.from('2020-11-01T01:45-07:00[America/Los_Angeles]').toString();
//2020-11-01T01:45:00-07:00[America/Los_Angeles]
轉(zhuǎn)換后
Temporal.ZonedDateTime.from('2020-11-01T01:45-07:00[America/Los_Angeles]').toInstant().toString();
//2020-11-01T08:45:00Z
ZonedTimeDate => PlainDateTime
轉(zhuǎn)換前
Temporal.ZonedDateTime.from('2020-11-01T01:45-07:00[America/Los_Angeles]').toString()
//2020-11-01T01:45:00-07:00[America/Los_Angeles]
轉(zhuǎn)換后
Temporal.ZonedDateTime.from('2020-11-01T01:45-07:00[America/Los_Angeles]').toPlainDateTime().toString();
//2020-11-01T01:45:00
PlainDateTime => ZonedTimeDate
轉(zhuǎn)換前
Temporal.PlainDateTime.from('2020-08-05T20:06:13').toString()
//2020-08-05T20:06:13
轉(zhuǎn)換后
Temporal.PlainDateTime.from('2020-08-05T20:06:13').toZonedDateTime('Asia/Tokyo').toString();
//2020-08-05T20:06:13+09:00[Asia/Tokyo]
總結(jié)
回到最開始 Date 的問(wèn)題。
1.不支持除用戶本地時(shí)間以外的時(shí)區(qū)。Temparal 支持開發(fā)人員通過(guò) TimeZone 來(lái)設(shè)置本地時(shí)間以外的時(shí)區(qū)。
2.計(jì)算 API 缺失。除了時(shí)區(qū)和日歷類型外,其他類型都可以進(jìn)行 算術(shù)運(yùn)算,即時(shí)間的比較,增加,減少等。
3.不支持非公歷,Calendar 類型支持 Temparal 選擇日歷。
4.解析器行為不可靠以至于無(wú)法使用,在 Temporal 里,new 構(gòu)造函數(shù)() 或者From 方法,對(duì)參數(shù)的要求都更加規(guī)范,同時(shí)From 方法支持 日期溢出 后的邏輯處理,可以防止系統(tǒng)崩潰。
最后附一張 Temparal 各種類型的功能對(duì)照?qǐng)D。每個(gè)類型負(fù)責(zé) Temparal 哪些功能已經(jīng)標(biāo)注清楚。
分享標(biāo)題:取而代之!以后不用再newDate()了
當(dāng)前路徑:http://www.5511xx.com/article/djposje.html


咨詢
建站咨詢
