Temporal API

JavaScript Temporal API:Date 的現代替代

JavaScript Date 幾十年來一直以眾所周知的方式存在缺陷。TC39 Temporal——自 2025 年初起為 Stage 4,已在現代瀏覽器和 Node.js 中發布——乾淨地分離了瞬間、掛鐘日期和帶時區的日期時間。本指南講解新的類型、它們如何對應 Unix 時間戳,以及如何遷移。

一眼看懂 Temporal vs Date

JavaScript 內建的 Date 幾十年來一直是已知的 bug 來源:它是可變的,只理解本地時區和 UTC,月份從 0 開始索引,剖析也只是寬鬆規定。Temporal 是走標準軌道的替代——Stage 4,並且是 ECMAScript 2026 的一部分——用專門設計的不可變類型修復了上述每個問題。下表是高層對比;本指南的其餘部分介紹這些類型以及它們如何對應 Unix 時間戳。

方面Date(舊)Temporal
可變性可變不可變
精度毫秒奈秒
時區僅本地 + UTC任意 IANA 時區(ZonedDateTime)
月份索引從 0 開始(0 = 一月)從 1 開始(1 = 一月)
剖析寬鬆,由實作定義嚴格的 ISO 8601 / RFC 9557
瞬間 vs 掛鐘混在一個類型裡分開的類型

為什麼有 Temporal

JavaScript Date 混淆了幾個不同的概念:一個精確瞬間、一個掛鐘時間,以及一個帶時區的日期時間。Date 還有眾所周知的剖析怪癖、單一時區(使用者的)和毫秒精度。Temporal 把底層概念公開為分開的類型,並支援奈秒精度、任意 IANA 時區和明確曆法體系。

  • 自 2025 年初起為 Stage 4;最先在 Firefox 139 中預設發布
  • 現在可在 Chrome 144+、Firefox 139+ 和 Node.js 26+ 中使用
  • polyfill(@js-temporal/polyfill)可在任何現代環境中運作
  • 設計為與 Date 共存——雙向都存在互通方法

Temporal 的核心類型

一小組類型乾淨地涵蓋了日期時間問題。每個都有一個規範的字串形式(ISO 8601,帶時區類型由 RFC 9557 擴充):

類型表示範例字串
Temporal.Instant一個精確瞬間,如 Unix 時間戳(ns 精度)2026-01-01T00:00:00Z
Temporal.ZonedDateTime瞬間 + IANA 時區 + 曆法2026-01-01T09:00:00+09:00[Asia/Tokyo]
Temporal.PlainDateTime日期 + 時間,無時區2026-01-01T09:00:00
Temporal.PlainDate一個曆法日期(如生日)2026-01-01
Temporal.PlainTime一個掛鐘時間09:00:00
Temporal.Duration一段時長,單位感知P3DT4H10M

使用 Unix 時間戳

Temporal.Instant 就是 Unix 時間戳類型。發布的 API 只公開毫秒和奈秒的 epoch 轉換——更早的 fromEpochSeconds 和 fromEpochMicroseconds 方法在 Stage 4 之前已被移除——所以把 Unix 秒乘以 1000 來轉換。儲存和傳輸用 Instant,當你需要某個時區的掛鐘檢視時用 ZonedDateTime。

  • Temporal.Now.instant() —— 目前的精確時刻
  • Temporal.Instant.fromEpochMilliseconds(Date.now()) —— 從 JS 毫秒時間戳
  • Temporal.Instant.fromEpochMilliseconds(1700000000 * 1000) —— 從 Unix 秒(× 1000)
  • Temporal.Instant.fromEpochNanoseconds(1700000000000000000n) —— 從奈秒(BigInt)
  • instant.epochMilliseconds 和 instant.epochNanoseconds —— 讀回 epoch 值
  • instant.toZonedDateTimeISO("America/New_York") —— 某個時區的掛鐘檢視

正確處理時區與 DST

ZonedDateTime 攜帶一個 IANA 時區,所以 DST 切換、空缺時間和重疊時間都被明確處理。消歧選項讓你為含糊的本地時間選擇一個策略,而規範的字串格式是 RFC 9557(一個帶方括號時區的 ISO 8601 時間戳)。

  • zdt.timeZoneId —— IANA 名稱(如 America/Los_Angeles)
  • zdt.add({ hours: 1 }) —— 以掛鐘方式進行的 DST 感知算術
  • zdt.until(zdt2) —— 兩個帶時區日期時間之間的距離
  • 消歧選項:"earlier"、"later"、"compatible"(預設 —— 空缺取較晚,重疊取較早)、"reject"
  • 往返:instant ↔ 帶時區日期時間是無損的

從 Date 遷移的模式

最簡單的遷移策略是先在邊界處(剖析輸入、格式化輸出)引入 Temporal,再逐步把內部邏輯遷過去。

  • Date → Instant:Temporal.Instant.fromEpochMilliseconds(date.getTime())
  • Instant → Date:new Date(instant.epochMilliseconds)
  • 對新程式碼,處處優先 Temporal,僅在 API 邊緣轉換為 Date
  • date-fns 和 Luxon 都有 Temporal 感知的模式/配接器
  • JSON:Temporal.Instant.prototype.toJSON 回傳一個 ISO 8601 字串

瀏覽器與執行階段支援

Temporal 於 2025 年發布,原生支援如今已廣泛,但尚未普及。在較舊的瀏覽器和 Safari 穩定版仍在使用期間,polyfill 是最穩妥的路徑。

  • Firefox 139+:最先發布,預設啟用(2025 年 5 月)
  • Chrome 144+:預設啟用(2026 年 1 月)
  • Node.js 26+:預設啟用(2026 年 5 月)
  • Safari:在 Technology Preview 中可用,尚未進入穩定版
  • polyfill:@js-temporal/polyfill 或 temporal-polyfill —— 相同的 API,任何現代環境

相關參考

FAQ

Temporal 是 Date 的替代嗎?
是——Temporal 旨在在新程式碼中完全取代 Date。Date 為向後相容仍保留在語言中,二者透過 epoch 毫秒互通。
如何把 Unix 時間戳轉換為 Temporal?
使用 Temporal.Instant.fromEpochMilliseconds()。對於 Unix 秒,乘以 1000:Temporal.Instant.fromEpochMilliseconds(seconds * 1000)。發布的 API 只有 fromEpochMilliseconds 和 fromEpochNanoseconds——較舊的 fromEpochSeconds 方法在 Temporal 達到 Stage 4 之前已被移除。
Temporal 支援奈秒嗎?
是。Temporal.Instant 內部具有奈秒精度,並以 BigInt 公開 epochNanoseconds。
今天可以在 Node.js 中用 Temporal 嗎?
在 Node.js 26+ 中,Temporal 預設啟用。在更舊的 Node 版本中,安裝 @js-temporal/polyfill——API 表面是相同的。
哪些瀏覽器支援 Temporal?
Firefox 139+(2025 年 5 月)、Chrome 144+(2026 年 1 月)和 Node.js 26+(2026 年 5 月)預設發布 Temporal。Safari 在 Technology Preview 中具備。對更舊的環境,使用 @js-temporal/polyfill。
Temporal 如何處理 DST 空缺?
ZonedDateTime 的建構函式和算術接受一個消歧選項。"compatible"(預設)為空缺選擇較晚的瞬間、為重疊選擇較早的瞬間;"reject" 在本地時間含糊時拋出錯誤。