Javascript 新特性前瞻 —— Temporal

2,637 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 2 天,点击查看活动详情

TC39

关于 TC39 的介绍可以看前一篇文章,这里不再赘述。

Temporal

今天要了解的新特性是 Temporal,这项特性提案时间为 2021 年 7 月,不到一年的时间已经进展到 stage-3 阶段,目前组委会已经在在做它的功能实现,有望在下个版本推出。

该项提案的初衷来自这篇文章,因为 JavaScript 最初关于日期的实现是照搬的 Java 方案,但由于各种限制和问题,Java 早在 1997 年就实现 Calendar 做了功能改进,而 JavaScript 时至今日用的还是老旧方案,改进优化实在是迫在眉睫。

Date 有什么问题

相信开发项目过程中,很多同学要么引入 momentdayjs 第三方库做时间处理,要么就是仓库里包含一堆处理时间的工具方法。举个最简单的例子,获取一周后的时间,用 Date 可以这样实现:

const getWeekTime = date => date.setDate(date.getDate() + 7

使用的时候大概这样:

let date = new Date();
let weekTime = getWeekTime(date)
console.log(date.getTime() === weekTime) // true

一方面我们定义了两个变量,另一方面你会发现结果 dateweekTime 是一样的值。也就是说在调用 setDate 方法的时候,会改变原本的 date。这显然不太合理,或者你会说不需要新的时间变量,直接加毫秒数:

const getWeekTime = time => time.getTime() + 7 * 24 * 60 * 60 * 10000

这样确实不会改变原来的时间,但总体不太优雅。Temporal 就优化了这一点,创造了不可变对象:

let date = Temporal.now.plainDateISO() // 2022-04-07
let week = date.add({days: 7})  // 2022-04-14

使用上述方法,原 date 对象不会变化,调用 add 方法可以很方便的得到想要的一周后时间。除了不可变性,Temporal 还有很多其他的功能。

Temporal 的能力

目前 Temporal 趋近完善,它的整体架构如图所示:

image.png 这张图很清晰的把一个时间各组成部分罗列出来,再结合官方 api 文档,你会发现基本上每一段时间格式都有对应的方法实现:

截屏2022-04-07 下午10.43.09.png 具体对应关系如下:

  • PlainDateTime- 日期和时间相结合。1995-12-07T15:00:00
  • PlainDate- 年、月和日。2030-07-14
  • PlainTime- 时间。13:37:00
  • PlainMonthDay- 月份和日期。08-05
  • PlainYearMonth- 年份和月份。2020-08
  • Now- 类似于当前的新Date()实现,返回当前时刻。
  • TimeZone- 时区。
  • Calendar- 任何日历扩展
  • ZonedDateTime- 整个日期和时间,带有时区扩展和日历扩展。
  • Instant- PlainDateTime 加上时区偏移量。
  • Duration- 定义持续时间,可以使用年、月、周、日、小时等。 举个简单的例子:
let myDate = Temporal.PlainDate.from({
    year: 2022,
    month: 04,
    day: 07,
    hour: 8,
    second: 0,
    minute: 44
});

myDate.year; // 2022
myDate.month; // 04
myDate.day; // 07
myDate.inLeapYear; // false
myDate.toString(); // 2022-03-28

月份不用像 Date 那样做加 1 处理,而且判断是否为闰年直接就给你提供了一个 inLeapYear 只读属性,直接告诉你是不是闰年,省去很多麻烦。另外还有一大堆好用的属性直击用户痛点给你答案:

const date1 = Temporal.PlainDate.from('2022-04-01');
const date2 = Temporal.PlainDate.from('2022-04-07');
const diffDays = date1.until(date2).days; // 6

另外 Temporal 还支持除公历外的其他日历,比如我们中国农历:

Temporal.PlainDate.from("2021-02-06").withCalendar("chinese").day;
// 返回的是农历 25

扩展和补充

如前所述,Temporal 每个时段都有自己的类实现,

截屏2022-04-07 下午11.25.32.png

每个类都定义的两个静态方法是

  • from:用于把时间转成符合自己的格式。这里以 PlainTime 为例
time = Temporal.PlainTime.from('03:24:30'); // => 03:24:30 
time = Temporal.PlainTime.from('1995-12-07T03:24:30'); // => 03:24:30 
time = Temporal.PlainTime.from('1995-12-07T03:24:30+01:00[Europe/Brussels]'); 
// => 03:24:30
  • compare(one, two):比较时间
    • −1 如果 one 比 two 时间早
    • 0 时间相同
    • 1 如果 one 时间晚于 two 还有比较使用的 until 方法,其实计算的是两个时间的 duration,然后对其进行我们想要的提取操作:
earlier = Temporal.PlainDate.from('2006-08-24'); 
later = Temporal.PlainDate.from('2019-01-31'); 
const time = earlier.until(later); // 后续处理

大体先介绍这么多,可以看到 temporal 功能强大,也带来了很多便捷的属性和方法,想要了解更多继续阅读官方文档。强烈期盼 Temporal 的到来!!

以上,感谢阅读。