Google Chrome 在最新版本(如Chrome 123及更高版本)中,正式启用了对 Temporal API 的支持,这标志着JavaScript原生日期时间处理能力的一次重大现代化升级。

为何我们需要Temporal API?
长期以来,开发者处理日期时间主要依赖原生的 Date 对象或第三方库,但它们存在明显的局限性。
原生 Date 对象的缺陷:
- 信息丢失:解析字符串后立即转换为时间戳,原始时区信息无法保留。
- 时区处理复杂:时区计算容易出错,API 设计不够直观。
- 功能单一:对多日历系统(如农历)缺乏原生支持。
主流第三方库的不足:
- day.js:虽然轻量,但功能相对有限,同样存在时区信息处理的问题。
- moment.js:功能全面但包体积较大,且已进入维护模式,不再添加新功能。
Temporal API 旨在成为 Date 对象的现代化、功能完备的替代方案。该提案目前处于 TC39 流程的第三阶段(Candidate),已在 MDN 发布文档,并开始在浏览器实验性版本中落地。
Temporal API的核心设计理念
1. 明确的时间类型区分
Temporal API 将时间概念进行了精细的划分,主要分为:
- Plain 类型:表示没有时区信息的“本地时间”(例如
2025-01-27T09:35)。
- Zoned 类型:包含明确时区标识的“绝对时间”(例如
2025-01-27T09:35+08:00[Asia/Shanghai])。
2. 严格的时区处理
与现有方案不同,Temporal 要求时区标识必须明确无误。
// ❌ 仅提供偏移量,缺少时区名称,解析失败
Temporal.ZonedDateTime.from("2025-01-27T09:35+08:00")
// RangeError: Temporal.ZonedDateTime requires a time zone ID in brackets
// ✅ 无偏移量,但有时区名称,API可自动推断
Temporal.ZonedDateTime.from("2025-01-27T09:35[Asia/Shanghai]")
// <2025-01-27T09:35:00+08:00[Asia/Shanghai]>
// ✅ 同时提供偏移量和时区名称
Temporal.ZonedDateTime.from("2025-01-27T09:35+08:00[Asia/Chongqing]")
// <2025-01-27T09:35:00+08:00[Asia/Chongqing]>
3. 多日历系统原生支持
Temporal 原生支持包括农历在内的多种日历系统,这对于需要处理国际化日期,特别是涉及数据库中存储特定文化日期数据的应用场景非常有用。
// 对比公历与农历的闰年
Temporal.Now.plainDateISO().inLeapYear // false (2025年为公历平年)
Temporal.Now.plainDateISO().withCalendar("chinese").inLeapYear // true (农历2025年置闰)
// 农历日期计算示例
const nyd = Temporal.ZonedDateTime.from("2025-01-29[Asia/Shanghai]")
const nextNyd = nyd.withCalendar('Chinese').add({ years: 1 })
// <2026-02-17T00:00:00+08:00[Asia/Shanghai][u-ca=chinese]>
Temporal API 基础使用示例
获取时间与创建对象
// 获取当前时间的瞬间(类似时间戳)
Temporal.Now.instant() // Temporal.Instant <2025-01-29T14:37:26.421844105Z>
Temporal.Now.instant().epochMilliseconds // 等价于 Date.now()
// 获取系统当前时区ID
Temporal.Now.timeZoneId() // "Asia/Shanghai"
// 创建日期时间对象
Temporal.PlainDateTime.from("2025-01-29")
Temporal.ZonedDateTime.from({
calendar: "chinese",
timeZone: "Asia/Shanghai",
year: 2025,
month: 1,
day: 1
})
日期格式化输出
const date = Temporal.Now.zonedDateTimeISO()
// 基础ISO格式输出
date.toString({ smallestUnit: "minutes", timeZoneName: "never" })
// "2025-01-29T14:35-05:00"
// 本地化字符串格式
date.toLocaleString("zh-CN")
// "2025/1/29 GMT-5 14:35:41"
// 使用 Intl API 进行高性能格式化(推荐)
const formatter = new Intl.DateTimeFormat("zh-CN", {
year: "numeric",
month: "long",
day: "numeric"
})
formatter.format(date)
日期运算与操作
// 获取指定月份的最后一天
const date = Temporal.PlainDate.from("2025-02-23")
date.with({ day: date.daysInMonth }) // 结果为 2025-02-28
// 处理农历节日(例如中秋节)
const midAutumn = Temporal.PlainMonthDay.from({
monthCode: "M08",
day: 15,
calendar: "chinese"
})
const midAutumn2025 = midAutumn.toPlainDate({ year: 2025 })
// Temporal.PlainDate <2025-10-06[u-ca=chinese]>
时区转换
const current = Temporal.Now.zonedDateTimeISO()
current.withTimeZone("Asia/Shanghai").toLocaleString("zh-CN")
// "2025/1/30 GMT+8 5:42:17"
处理复杂的日期时间字符串
Temporal API 没有单一的“万能”解析函数,需要根据输入字符串的格式选择对应的解析方法。
function parseStringDate(s) {
const parsers = [
// 情况1:字符串包含完整时区信息(如 [Asia/Shanghai])
() => Temporal.ZonedDateTime.from(s),
// 情况2:字符串包含偏移量但无时区名(如 +08:00)
() => Temporal.Instant.from(s).toZonedDateTimeISO(s),
// 情况3:纯日期时间字符串(无时区)
() => Temporal.PlainDateTime.from(s).toZonedDateTime(Temporal.Now.timeZoneId())
]
for (const parser of parsers) {
try {
return parser()
} catch {
continue
}
}
return null
}
// 使用示例
parseStringDate("2025-02-03T12:31+08:00") // 带偏移量
parseStringDate("2025-02-03T12:31") // 纯日期时间
parseStringDate("2025-02-03") // 纯日期
随着 Chrome 的正式支持,Temporal API 为前端开发者提供了一套强大、精确且符合现代工程实践的日期时间处理工具链,有望彻底解决以往在日期计算、时区转换和多日历支持上的诸多痛点。