Node.js 26正式启用了Temporal API,这是JavaScript处理日期和时间的全新标准。如果你已经受够了Date对象的坑——可变性、时区混乱、月份从0开始——这篇教程将带你从零掌握Temporal API的所有核心用法。
为什么Temporal比Date好?
先看一个经典的Date坑:
const d = new Date(2026, 0, 1); // 注意:月份从0开始!
console.log(d.getMonth()); // 0,不是1
// Date是可变的,这会导致bug
const d1 = new Date('2026-01-01');
const d2 = d1;
d2.setMonth(5);
console.log(d1.getMonth()); // 5!d1也被改了
Temporal解决了这些问题。所有Temporal对象都是不可变的,月份从1开始,时区处理清晰明确。
核心类型一览
| 类型 | 用途 | 示例 |
|---|---|---|
| PlainDate | 只有日期,没有时间和时区 | 2026-05-20 |
| PlainTime | 只有时间,没有日期和时区 | 14:30:00 |
| PlainDateTime | 日期+时间,没有时区 | 2026-05-20T14:30:00 |
| ZonedDateTime | 日期+时间+时区(最常用) | 2026-05-20T14:30:00+08:00[Asia/Shanghai] |
| Instant | 精确到纳秒的时间点 | 2026-05-20T06:30:00Z |
| Duration | 时间段 | P1Y2M3DT4H5M6S |
12种常见用法
1. 获取当前时间
// 当前时区的日期时间
const now = Temporal.Now.zonedDateTimeISO();
console.log(now.toString());
// 2026-05-20T14:30:00.000+08:00[Asia/Shanghai]
// 当前日期
const today = Temporal.Now.plainDateISO();
console.log(today.toString());
// 2026-05-20
// UTC时间点
const instant = Temporal.Now.instant();
console.log(instant.toString());
// 2026-05-20T06:30:00Z
2. 创建指定日期
// 创建日期对象
const date = Temporal.PlainDate.from('2026-12-25');
console.log(date.year); // 2026
console.log(date.month); // 12(不是0!)
console.log(date.day); // 25
// 从对象创建
const date2 = Temporal.PlainDate.from({ year: 2026, month: 6, day: 1 });
3. 创建带时区的日期时间
// 北京时间
const beijing = Temporal.ZonedDateTime.from(
'2026-05-20T14:30:00+08:00[Asia/Shanghai]'
);
// 从components创建
const tokyo = Temporal.ZonedDateTime.from({
year: 2026, month: 5, day: 20,
hour: 15, minute: 30,
timeZone: 'Asia/Tokyo'
});
4. 日期加减运算
const today = Temporal.Now.plainDateISO();
// 加3个月
const future = today.add({ months: 3 });
// 减7天
const lastWeek = today.subtract({ days: 7 });
// 加2年3个月15天
const futureDate = today.add({ years: 2, months: 3, days: 15 });
5. 计算两个日期的差
const start = Temporal.PlainDate.from('2026-01-01');
const end = Temporal.PlainDate.from('2026-12-31');
const diff = end.since(start);
console.log(diff.toString()); // P364D
// 按不同单位计算
console.log(end.since(start, { largestUnit: 'months' }).toString());
// P11M30D
console.log(end.since(start, { largestUnit: 'years' }).toString());
// P11M30D
6. 时区转换
const now = Temporal.Now.zonedDateTimeISO();
console.log(now.toString());
// 2026-05-20T14:30:00+08:00[Asia/Shanghai]
// 转换到东京时间
const tokyo = now.withTimeZone('Asia/Tokyo');
console.log(tokyo.toString());
// 2026-05-20T15:30:00+09:00[Asia/Tokyo]
// 转换到纽约时间
const ny = now.withTimeZone('America/New_York');
console.log(ny.toString());
// 2026-05-20T02:30:00-04:00[America/New_York]
7. 格式化输出
const date = Temporal.PlainDate.from('2026-05-20');
// 自定义格式
const formatted = date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
});
console.log(formatted); // 2026年5月20日星期三
// ISO格式
console.log(date.toString()); // 2026-05-20
8. 比较日期
const a = Temporal.PlainDate.from('2026-01-01');
const b = Temporal.PlainDate.from('2026-12-31');
console.log(Temporal.PlainDate.compare(a, b)); // -1 (a < b)
console.log(a.equals(b)); // false
console.log(a.toString() === b.toString()); // false
9. Duration(时间段)
// 创建时间段
const dur = Temporal.Duration.from({ hours: 2, minutes: 30 });
console.log(dur.toString()); // PT2H30M
// 用Duration做日期运算
const now = Temporal.Now.zonedDateTimeISO();
const later = now.add(dur);
console.log(later.toString());
// Duration可以规范化
const messy = Temporal.Duration.from({ minutes: 90 });
const normalized = messy.round({ largestUnit: 'hours' });
console.log(normalized.toString()); // PT1H30M
10. 获取日期信息
const date = Temporal.PlainDate.from('2026-05-20');
console.log(date.dayOfWeek); // 3 (星期三,1=周一,7=周日)
console.log(date.dayOfYear); // 140
console.log(date.weekOfYear); // 21
console.log(date.daysInMonth); // 31
console.log(date.inLeapYear); // false
11. 月份第一天/最后一天
const date = Temporal.Now.plainDateISO();
// 本月第一天
const firstDay = date.with({ day: 1 });
// 本月最后一天
const lastDay = date.with({ day: date.daysInMonth });
// 本年第一天
const yearStart = date.with({ month: 1, day: 1 });
12. 与旧代码互操作
// Temporal → Date
const plainDate = Temporal.PlainDate.from('2026-05-20');
const jsDate = new Date(plainDate.toString());
// Date → Temporal
const fromJsDate = Temporal.Instant.fromEpochMilliseconds(
jsDate.getTime()
);
const zdt = fromJsDate.toZonedDateTimeISO('Asia/Shanghai');
注意事项
- 浏览器支持:目前Temporal API主要在Node.js 26+中可用,浏览器支持还在推进中。如果需要在浏览器中使用,可以使用temporal-polyfill
- 性能:对于简单的日期操作,Date对象可能更快。Temporal的优势在于正确性和可维护性
- 库兼容性:大部分日期处理库(如date-fns、dayjs)还不直接支持Temporal对象,需要先转换
迁移建议
对于现有项目,不需要立即全面迁移。建议:
- 新代码直接使用Temporal API
- 在重构日期相关代码时,逐步替换Date对象
- 在测试环境中全面验证后再上线
本文参考来源:Node.js 26.0.0 Release Notes | TC39 Temporal Proposal
© 版权声明
THE END














暂无评论内容