temporal 提案用新模型解决夏令时问题,基于 iana 数据库和明确类型语义;zoneddatetime 绑定动态时区处理真实事件时间,拒绝非法时刻,保留歧义选项;跨时区运算须经 instant;业务语义需显式锚定时区;plaindatetime 存储无时区信息;timezone 实例实时查库获取偏移。

Temporal 提案不是给 Date 打补丁,而是用一套新模型把夏令时问题从“不可靠猜测”变成“可验证计算”。它不依赖运行时本地设置,不静默修正非法时间,也不在加减操作中偷偷改变时长——所有行为都基于 IANA 时区数据库和明确的类型语义。
用 ZonedDateTime 替代字符串或 Date 表示真实事件时间
会议、航班、订单创建这类有物理发生地的时间,必须绑定动态时区(如 America/New_York),而不是静态偏移(如 +05:00)。ZonedDateTime 在构造时就查时区规则,自动识别 DST 切换日是否允许某个时刻存在。
- 夏令时开始日(如 2026-03-09 凌晨 2:00 跳至 3:00):
PlainDateTime.from('2026-03-09T02:30').toZonedDateTimeISO('America/New_York')会直接抛RangeError,拒绝构造非法时间 - 夏令时结束日(如 2026-11-02 凌晨 2:00 重复出现):同一 PlainDateTime 可成功转为两个不同 Instant,ZonedDateTime 明确保留歧义选项(通过
disambiguation参数控制) - 避免用
new Date('2026-03-09T02:30-05:00')—— 它把 +05:00 当作固定偏移,完全忽略当天实际是 EDT(UTC−4)还是 EST(UTC−5)
跨时区加减必须统一到 Instant 再转换
ZonedDateTime 的 .add() 按日历语义推进(比如“加一天”可能跨越 DST 边界,导致实际毫秒数不等于 24 小时),而真正需要恒定时间间隔的场景(如定时任务、SLA 计算),必须先转成 Instant。
- 错误写法:
zdt.add({days: 1})→ 在 DST 开始日返回比预期早一小时的时刻 - 正确流程:
zdt.toInstant().add({hours: 24}).toZonedDateTimeISO('Asia/Tokyo')→ 先用纳秒精度做线性运算,再按目标时区渲染 - 所有涉及“X 小时后”“Y 天内”的逻辑,起点和终点都应是 Instant,ZonedDateTime 仅用于输入解析与结果展示
业务语义中的“今天”“本月”必须显式锚定用户/业务时区
“今天”不是全局概念。一个部署在 UTC 的服务调用 Temporal.Now.plainDateTimeISO() 得到的是 UTC 时间,不能直接当作东京用户的“今日零点”。
- 获取用户视角的今日零点:
Temporal.Now.zonedDateTimeISO('Asia/Tokyo').withPlainTime('00:00').withPlainDate(Temporal.Now.plainDateISO()) - 统计报表按纽约财年计算:
Temporal.PlainDateTime.from('2026-04-01').toZonedDateTimeISO('America/New_York')才是该时区真正的 4 月 1 日起始时刻 - 表单录入的“营业时间”“生日”等无时区信息,一律用 PlainDateTime 存储,禁止用 Date 或带偏移字符串隐式绑定环境时区
避免手动处理偏移,让 TimeZone 实例自动查库
Date.prototype.getTimezoneOffset() 返回的是当前浏览器时区此刻的偏移值,无法反映历史或未来某时刻的真实偏移(比如 2025 年 11 月的 EST 偏移是 −5,但 2026 年 3 月的 EDT 是 −4)。Temporal.TimeZone 则每次调用都实时查 IANA 数据库。
- 查某时刻在伦敦的偏移:
Temporal.TimeZone.from('Europe/London').getOffsetNanosecondsFor(instant) - 判断某时间是否处于 DST:
timeZone.getOffsetNanosecondsFor(instant) !== timeZone.getOffsetNanosecondsFor(instant.subtract({days: 30})) - 迁移旧代码时,用
Temporal.Instant.fromEpochMilliseconds(date.getTime())提取原始时间点,再交由 Temporal 重新解释,而非继续依赖 Date 的 toString() 或 toLocaleString()










