这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」
在JavaScript中,日期的处理是非常简陋的。自从1995年受到Java的启发实现了 Date()对象以来,Date()就再也没有发生过迭代。随着时间的推移,java选择了放弃Date(),但是浏览器为了向后兼容,所以Date()一直保留在 JavaScript 中。
Date()的问题在于:
- 过于简陋
- 它只支持 UTC 和用户的 PC 时间
- 它不支持除格里高利历以外的日历
- 字符串到日期解析很容易出现错误
- 日期对象是可变的。例如:
const today = new Date();
const tomorrow = new Date( today.setDate( today.getDate() + 1 ) );
console.log( tomorrow ); // 打印的tomorrow的时间
console.log( today ); // 打印出相同的内容
开发者经常会使用诸如 moment.js这样的日期库,但是它占有74KB的空间,时间同样是可变的。像Day.js或者date-fns这样的库或许会是更好地替代品。但是当你的程序中只要很少的时间处理的功能,是否需要去使用一个日期库呢?
浏览器为了兼容性,需要继续支持Date(),但是一个全新的静态时间对象的提案正处在TC39标准批准流程的第三阶段的候选方案中。这个新的API解决了上面所有提出的问题,Chrome 浏览器将会很快就推出这个新的API。但是他可能不会在2022年底进行推广使用,所以要小心兼容性产生的问题。
当前日期及时间
Temporal.Now 会返回一个当前日期和时间的对象:
// 时间同样和Date一样,从1970年1月开始,也就是北京时间1970年1月08:00:00
Temporal.Now.instant().epochSeconds;
Temporal.Now.instant().epochMilliseconds;
// 本地时间
Temporal.Now.zonedDateTimeISO();
// 当前时区
Temporal.Now.timeZone();
// 另一个时区的当前时间
Temporal.Now.zonedDateTimeISO('Europe/London');
当前日期和时间
Temporal.Instant会返回一个以纳秒为单位的最接近的,并且符合ISO8601标准的字符串来表示日期和时间格式的对象。
Temporal.Instant.from('2022-03-04T05:56:78.999999999+02:00[Europe/Berlin]');
Temporal.Instant.from('2022-03-04T05:06+07:00');
还可以使用 epoch 格式的值:
Temporal.Instant.fromEpochSeconds(1.0e8);
时区日期和时间
Temporal.ZonedDateTime将会返回一个在指定时区上的指定日期和时间,例如:
new Temporal.ZonedDateTime(
1234567890000, // 时间戳
Temporal.TimeZone.from('Europe/London'), // 时区
Temporal.Calendar.from('iso8601') // 默认日历格式
);
Temporal.ZonedDateTime.from('2025-09-05T02:55:00+02:00[Africa/Cairo]');
Temporal.Instant('2022-08-05T20:06:13+05:45').toZonedDateTime('+05:45');
Temporal.ZonedDateTime.from({
timeZone: 'America/New_York'
year: 2025,
month: 2,
day: 28,
hour: 10,
minute: 15,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0
});
计划日期和时间
计划时间/日期是指在不考虑时区的情况下实现的简单的日历事件。例如:
-
Temporal.PlainTime指定一个特殊的时间,例如 在每个工作日下午三点举行会议// 以下全都表示为 15:00:00 new Temporal.PlainTime(15, 0, 0); Temporal.PlainTime.from('15:00:00'); -
Temporal.PlainDate指定一个特殊的日期,例如你需要在2022年1月31日前提交报税表// 一下都表示2022年1月31日 new Temporal.PlainDate(2022, 1, 31); Temporal.PlainDate.from('2022-01-31'); -
Temporal.PlainDateTime指定一个不分时区的日期合时间new Temporal.PlainDateTime(2022, 5, 4, 10, 11, 12); Temporal.PlainDateTime.from('2022-05-04T10:11:12'); -
Temporal.PlainYearMonth指定某一个月的计划。例如2022年6月计划已经完成new Temporal.PlainYearMonth(2022, 6); Temporal.PlainYearMonth.from('2022-06'); -
Temporal.PlainMonthDay指定不限年份的时间,例如:十月一日是国庆:new Temporal.PlainMonthDay(10, 1); Temporal.PlainMonthDay.from('10-01');
开源会话重播
在生产环境中,调试web应用可能是非常耗时又困难的。OpenReplay是一个可以替代 FullStory、 LogRocket 和 Hotjar 的开源开源产品。它可以帮助你监听和回放用户的所有操作,并且会告诉你是如何处理用户的每一步操作的。就犹如你打开了控制台并看着用户在操作一样。OpenReplay是目前唯一可用的开源产品。
日期和时间值
你可以从指定时区的时间值中获取到你想要的信息,例如:
const t1 = Temporal.ZonedDateTime.from('2022-12-07T03:24:30+02:00[Africa/Cairo]');
你可以从中获取到:
t1.year; // 2022
t1.month; // 12
t1.day; // 7
t1.hour; // 3
t1.minute; // 24
t1.second; // 30
t1.millisecond; // 0
t1.microsecond; // 0
t1.nanosecond; // 0
其他特性:
dayOfWeek— 周一返回1,周天返回7dayOfYear— 返回1到365或366weekOfYear— 返回1-到52或者53daysInMonth— 返回28、29、30或31daysInYear— 返回365或者366inLeapYear— 闰年返回true,平年返回false
日期和时间的比较和排序
所有 Temporal对象都包含一个.compare(date1, date2) 方法,该方法返回:
0==> date1和date2相等1==> date1大于date2-1==> date1小于date2 例如:
const
date1 = Temporal.Now,
date2 = Temporal.PlainDateTime.from('2022-05-04');
Temporal.ZonedDateTime.compare(date1, date2);
// 1
你可以将compare()函数作为sort函数的参数传入来实现日期的升序/降序排列:
const t = [
'2022-01-01T00:00:00+00:00[Europe/London]',
'2022-01-01T00:00:00+00:00[Africa/Cairo]',
'2022-01-01T00:00:00+00:00[America/New_York]'
].map( d => Temporal.ZonedDateTime.from(d) )
.sort( Temporal.ZonedDateTime.compare );
日期和时间的计算
Temporal对象将提供计算方法: add(), subtract(), 和 round() :
你可以通过Temporal.Duration object 定义一个开始时间,然后可以分别以years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, and nanoseconds为单位来计算时间,或者使用sign键用1或者-1来表示相反的运算。这些方法都仅支持一段时间,所以不需要创建一个指定的实践对象。例如:
const t1 = Temporal.ZonedDateTime.from('2022-05-04T00:00:00+00:00[Europe/London]');
// 增加8小时59分
t1.add({ hours: 8, minutes: 59 }); // 或者
t1.add(Temporal.Duration.from({ hours: 8, minutes: 59 }));
// 减少两周
t1.subtract({ weeks: 2 }); // 或者
t1.add({ weeks: 2, sign: -1 });
// 最近的一个月
t1.round({ smallestUnit: 'month' });
使用until() 和since() 方法可以返回一个Temporal.Duration 对象,他可以基于某一个日期/时间来返回直到某一个时间或者从某个时间开始的时间范围,例如:
// months to t1
t1.until().months;
// days to t2
t2.until().days;
// weeks since t3
t3.since().weeks;
equals()可以实现判断两个时间是否相等,例如:
const
d1 = Temporal.PlainDate.from('2022-01-31');
d2 = Temporal.PlainDate.from('2023-01-31');
d1.equals(d2); // false
格式化日期和时间字符串
Temporal对象都包含一个.toString() 来返回一个字符串,例如:Temporal. now.toString () :
2022-09-05T02:55:00+02:00[Europe/London]
这种表示格式对用户来说是不友好的,所以国际化API提供了一个更方便的本地化方法,例如:
// 初始化时间
const d = new Temporal.PlainDate(2022, 3, 14);
// 美式时间格式: 3/14/2022
new Intl.DateTimeFormat('en-US').format(d);
// 英式时间格式: 14/03/2022
new Intl.DateTimeFormat('en-GB').format(d);
// 西班牙时间格式: miércoles, 14 de abril de 2022
new Intl.DateTimeFormat('es-ES', { dateStyle: 'full' }).format(d);
Temporal Time
我们从一开始就接受了不方便的Date对象,Temporal的出现,将会给JavaScript开发者带来些许的期待。以后我们将脱离使用日期库的烦恼。