本文作者王明是360导航前端团队前端开发工程师

原文标题:JS历史最头疼的对象Date即将淘汰,替代物Temporal真的好用(全网首发Temporal教程)

Date背景


日期处理javajava.Util.DateJava

Date存在的问题


  • 不支持除用户本地时间以外的时区

时区信息
  • 解析器行为不可靠以至于无法使用

new Date(); 
new Date(value); 
new Date(dateString); 
new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);
输入的参数格式问题('2022-02-22')(2022,02,22)
  • 计算 API 缺失

比较两个时间的长短时间之间的加减运算
  • 不支持非公历

公历农历

Temporal的诞生


DateDateDateTemporal
TemporalTemporal
$ npm install @js-temporal/polyfill
import { Temporal} from '@js-temporal/polyfill';

TemporalMathPromise

4c847f93b73010964b82cb78b37aca44.png

WechatIMG258.jpeg
Temporal
ISO 8601日期和时间
时区
日历
ISO 8601格式

对比 Date

new Date()
//Fri Jan 28 2022 17:03:11 GMT+0800 (中国标准时间)
Date时区和历法

Temporal各种类型介绍


Temporal类型转换
功能关系Temporal
TemporalTemporal

377d05889c48babcdf7b89f15c257a2b.png

exxqq.png

ZonedDateTime

Temporal特定区域特定时刻
北京时间2008年5月12日14时28分4秒纽约时间2008年5月12日01时28分4秒
如何获得一个 ZonedDateTime 类型?

Temporalnew 构造函数()from方法
  • new 构造函数()方式

参数:(纳秒数,时区,日历),不同类型要求的参数不同

Unix 纪元
Temporal
new Temporal.ZonedDateTime(0n, 'Asia/Shanghai', 'chinese'); 
//Temporal.ZonedDateTime <1970-01-01T08:00:00+08:00[Asia/Shanghai][u-ca=chinese]>
TemporaltoString()Object.prototype.toString()Temporal
toString()
new Temporal.ZonedDateTime(0n, 'Asia/Shanghai', 'chinese').toString(); 
//1970-01-01T08:00:00+08:00[Asia/Shanghai][u-ca=chinese]
1970-01-01T08:00:00+08:001970-01-01T00:00:00+00:00
Temporal
溢出处理Temporal

接受字符串

Temporal.ZonedDateTime.from('2022-02-28T00:00:00+08:00[Asia/Shanghai]').toString(); 
//2022-02-28T00:00:00+08:00[Asia/Shanghai]

or

接受对象,({时区,日期,日历},options)

容错机制日期溢出{ overflow: 'constrain' }{ overflow: 'reject' }
constrain溢出处理
//输入 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
Temporal.ZonedDateTime.from({ timeZone: 'Asia/Shanghai', year: 2022, month: 2, day: 31}, { overflow: 'reject' }).toString(); 
//RangeError: value out of range: 1 <= 31 <= 28

Instant

定义:负责单个时间点(称为 “精确时间” ),精度以纳秒为单位。不存在时区和日历信息。

2020-01-23T17:04:36.491865121-08:00瞬间
Instant

new Temporal.Instant( bigint )

Unix 纪元
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
ISO 8601

Temporal.Instant.from(thing: any)

Instant
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');

虽然前两个携带了时区信息,但获取到的Instant 时间值相同,三个都是 2019-03-30T00:45Z

Plain XX系列

Temporal
农历下午2:00
InstantInstantPlain XX

PlainDateTimePlaindatePlaintimePlainYearMonthPlainMonthDay
PlainDateTime
PlainDateTime

new Temporal.PlainDateTime(year,month,day...)

年 -> 纳秒
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

Temporal
东八区
TimeZone

new Temporal.TimeZone(string)

string:对一个时区的描述

//东八区,即北京时间
new Temporal.TimeZone('8:00');
//直接字符串描述,前提是 Temporal 内部有定义
new Temporal.TimeZone('Asia/Shanghai');
//Asia/Shanghai

from同理

Temporal.TimeZone.from('Asia/Shanghai');
//Asia/Shanghai

在和其他类型搭配时,可以直接使用字符串(“Asia/Shanghai”),或者 Temporal.TimeZone对象

例子:

ZonedDateTimeTemporal.TimeZone
new Temporal.ZonedDateTime(0n, Temporal.TimeZone.from('Asia/Shanghai')); 
//1970-01-01T08:00:00+08:00[Asia/Shanghai]
等价于
new Temporal.ZonedDateTime(0n, 'Asia/Shanghai'));

Calendar

Temporal
农历
Calendar

TimeZone
new Temporal.Calendar('chinese').toString();
//chinese
Temporal.Calendar.from('chinese').toString();
//chinese
Calendar日历属性
日历属性plainXX系列ZonedDateTime
withCalendar

例子:

plainXX系列 添加日历属性

没有添加日历属性前
Temporal.PlainDate.from('2019-02-06');
//2019-02-06
添加日历属性后
Temporal.PlainDate.from('2019-02-06').withCalendar('chinese');
//2019-02-06[u-ca=chinese]

ZonedDateTime 添加日历属性

没有添加日历属性前
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

算术
一小时一分钟一小时十分钟Duration
DurationDateISO 8601
ISO 8601PT
DurationPT

举例:

P1YPT
PT1MPT
Duration

cffed7f141505bd98bbe05846bf0ec01.png

JUEJIN.png
Duration

new Temporal.Duration()

undefined0
new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 654, 321); 
// P1Y2M3W4DT5H6M7.987654321S  
//中文翻译 => 1年2月3周4天5小时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
DurationDuration日期与时间
日期或时间
Durationcompare
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
onetwo
onetwo
onetwo
TimezoneCalendar算术
PlainDateTime
one = Temporal.PlainDateTime.from('1995-12-07T03:24');
two = Temporal.PlainDateTime.from('1995-12-07T01:24');
Temporal.PlainDateTime.compare(two,two)
//1

日期或时间

加法:

Temporal.Duration.from('PT1H'); //PT1H
hour.add({ minutes: 30 }); 
// => PT1H30M

减法:

hourAndAHalf = Temporal.Duration.from('PT1H30M'); //PT1H30M
hourAndAHalf.subtract({ hours: 1 }); // => PT30M
TimezoneCalendar
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类型之间的转换

类型转换

51a3d8293f0d745f61fd3447cb5079c9.png

exxqq.png
通道桥梁

Instant  =>  ZonedTimeDate

转换前
Temporal.Instant.from('2020-08-05T20:06:13+0900').toString()
//2020-08-05T11:06:13Z
转换后
Temporal.Instant.from('2020-08-05T20:06:13+0900').toZonedDateTimeISO('Asia/Tokyo').toString();
//2020-08-05T20:06:13+09:00[Asia/Tokyo]

ZonedTimeDate => Instant

转换前
Temporal.ZonedDateTime.from('2020-11-01T01:45-07:00[America/Los_Angeles]').toString();
//2020-11-01T01:45:00-07:00[America/Los_Angeles]
转换后
Temporal.ZonedDateTime.from('2020-11-01T01:45-07:00[America/Los_Angeles]').toInstant().toString();
//2020-11-01T08:45:00Z

ZonedTimeDate  => PlainDateTime

转换前
Temporal.ZonedDateTime.from('2020-11-01T01:45-07:00[America/Los_Angeles]').toString()
//2020-11-01T01:45:00-07:00[America/Los_Angeles]
转换后
Temporal.ZonedDateTime.from('2020-11-01T01:45-07:00[America/Los_Angeles]').toPlainDateTime().toString();
//2020-11-01T01:45:00

PlainDateTime =>  ZonedTimeDate

转换前
Temporal.PlainDateTime.from('2020-08-05T20:06:13').toString()
//2020-08-05T20:06:13
转换后
Temporal.PlainDateTime.from('2020-08-05T20:06:13').toZonedDateTime('Asia/Tokyo').toString();
//2020-08-05T20:06:13+09:00[Asia/Tokyo]

总结


Date
TemparalTimeZone
算术运算
CalendarTemparal
Temporalnew 构造函数()FromFrom日期溢出

Temparal功能Temparal

fad4bb05ba341bf4ce5ec9028b676267.png

功能图.png

参考资料

[1]

博客: https://tc39.es/proposal-temporal/docs/

 - END -

e10e7645b2b5e4135f061b845f60fdcb.png

关于奇舞团

奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

584fe4ba5942f64ccce6aaedb96ba48d.png