在 JavaScript 中處理 Unix 時間戳
在 JavaScript 中處理 Unix 時間戳所需的一切 —— 取得目前時間、從時間戳建立 Date、為任意時區格式化、避免常見錯誤 —— 附一份可複製貼上的速查表和深入指南的連結。
JavaScript 時間戳速查表
JavaScript 以毫秒運作:Date.now() 和 Date 建構函式都使用自 Unix 紀元起的毫秒,而其他大多數系統使用秒 —— 所以幾乎每個 JavaScript 時間戳任務都歸結為記住一個 × 1000 或 ÷ 1000。下表是快速參考;其後的各節解釋每個操作,深入指南則完整講解時區和 Temporal API。
| 任務 | 程式碼 | 結果 |
|---|---|---|
| 目前時間(毫秒) | Date.now() | 1700000000000 |
| 目前時間(秒) | Math.floor(Date.now() / 1000) | 1700000000 |
| 秒 → Date | new Date(s * 1000) | Date 物件 |
| 毫秒 → Date | new Date(ms) | Date 物件 |
| Date → 毫秒 | date.getTime() | 1700000000000 |
| Date → ISO 8601 | date.toISOString() | 2023-11-15T06:13:20.000Z |
| ISO 字串 → 毫秒 | Date.parse(str) | 1700000000000 |
取得目前 Unix 時間戳
JavaScript 提供了幾種等價的方式把目前時間取得為數字時間戳。它們都回傳自 Unix 紀元起的毫秒數。
- Date.now() → 最快也最易讀 —— 1700000000000(毫秒)
- Math.floor(Date.now() / 1000) → 秒級 Unix 時間戳 —— 1700000000
- +new Date() → 與 Date.now() 相同,使用一元加運算子
- new Date().getTime() → 明確的方法呼叫,結果與 Date.now() 相同
從 Unix 時間戳建立 Date 物件
Date 建構函式接受自紀元起的毫秒。把秒級時間戳傳給建構函式之前,務必先乘以 1000。
- new Date(1700000000 * 1000) → 從秒(最常見的情形)
- new Date(1700000000000) → 從毫秒(JavaScript 的 API、Java)
- new Date(Date.now()) → 目前時間作為 Date 物件
- new Date(0) → Unix 紀元:1970 年 1 月 1 日 00:00:00 UTC
格式化日期 —— 內建字串方法
Date 物件有幾個內建的字串轉換方法。每個都產生不同的格式。
- .toISOString() → '2023-11-15T06:13:20.000Z' — ISO 8601,始終 UTC,機器可讀
- .toUTCString() → 'Wed, 15 Nov 2023 06:13:20 GMT' — RFC 7231,人類可讀的 UTC
- .toString() → 帶完整時區名的本地時區字串
- .toLocaleString() → 在使用者本地時區下感知地區設定的格式
感知時區的格式化
對於感知時區的格式化,用帶明確 timeZone 的 Intl.DateTimeFormat —— 它會自動套用 DST,且不需要函式庫。時區本身就是一個深入的主題;專門的 JavaScript 時區指南講解 formatToParts、偵測使用者時區,以及困難的掛鐘→UTC 方向。
- new Intl.DateTimeFormat('en-US', { timeZone: 'America/New_York', dateStyle: 'full', timeStyle: 'long' }).format(date)
- date.toLocaleString('en-GB', { timeZone: 'Europe/London', hour12: false })
把日期字串轉換回 Unix 時間戳
要走相反方向 —— 從日期字串到 Unix 時間戳 —— 用 Date.parse(),或把字串傳給 Date 建構函式。
- new Date('2023-11-15T06:13:20Z').getTime() / 1000 → 從 ISO 8601 UTC 得到 Unix 秒
- new Date('2023-11-15T01:13:20-05:00').getTime() → 從帶偏移的 ISO 得到 Unix 毫秒
- Date.parse('2023-11-15T06:13:20Z') → 與 new Date(...).getTime() 相同
- 為了可預測的剖析,始終使用帶明確時區的 ISO 8601 格式
常見陷阱
這些是 JavaScript 開發者在日期和時間戳上最常犯的錯誤:
- new Date(1700000000) —— 缺少 × 1000 會轉換到約 1970 年而非 2023 年
- getMonth() 回傳 0–11 而非 1–12 —— 顯示時務必加 1
- new Date('2024-01-01') 是 UTC 午夜;new Date('2024/01/01') 是本地午夜
- new Date(2024, 0, 1) = 1 月 1 日(建構函式裡月份也是從 0 開始)
- 用加 86400000 毫秒來得到「明天」可能在 DST 邊界失敗 —— 改用 setDate(d.getDate() + 1)
Temporal API —— Date 的現代替代
TC39 的 Temporal API 已達到 Stage 4,並在現代瀏覽器和 Node.js 中發布。它修復了 Date 的核心缺陷 —— 不可變、奈秒精度、感知時區 —— 而 Temporal.Instant 就是它的 Unix 時間戳類型。發布的 API 以毫秒或奈秒轉換紀元(較舊的 fromEpochSeconds 已被移除),所以把 Unix 秒乘以 1000。完整 API 見 Temporal 完整指南。
- Temporal.Now.instant() —— 奈秒精度的目前瞬間
- Temporal.Instant.fromEpochMilliseconds(Date.now()) —— 從 JS 毫秒時間戳
- Temporal.Instant.fromEpochMilliseconds(1700000000 * 1000) —— 從 Unix 秒(× 1000)
- Temporal.ZonedDateTime —— 瞬間 + IANA 時區,Date 本該是的類型
- 已在 Firefox 139+、Chrome 144+、Node.js 26+ 發布;Safari 在 Technology Preview;其餘用 polyfill
進一步閱讀
FAQ
- 在 JavaScript 中如何取得秒級 Unix 時間戳?
- 用 Math.floor(Date.now() / 1000)。Date.now() 回傳毫秒,所以除以 1000 再向下取整即可得到整數 Unix 秒。
- 在 JavaScript 中如何把 Unix 時間戳轉換為可讀日期?
- 把秒乘以 1000,傳給 Date 建構函式,再格式化:new Date(1700000000 * 1000).toISOString() 得到 "2023-11-14T22:13:20.000Z"。對於特定時區,用帶 timeZone 選項的 Intl.DateTimeFormat。
- 為什麼用 Unix 時間戳呼叫 new Date() 會顯示 1970?
- Date 建構函式預期毫秒。10 位的秒級時間戳必須乘以 1000:new Date(seconds * 1000)。
- 如何為特定時區格式化 JavaScript 日期?
- 用帶明確 timeZone 選項的 Intl.DateTimeFormat,例如 new Intl.DateTimeFormat('en-US', { timeZone: 'America/New_York' })。它會自動套用日光節約時間,且不需要外部函式庫。
- 我該用 Date 還是 Temporal?
- 對於執行階段支援的新程式碼,優先用 Temporal —— 它不可變、感知時區,並能避開 Date 的坑。Date 對簡單的 epoch 毫秒工作仍然沒問題,而且依舊是支援最廣的。