博客 / 詳情

返回

藍易雲cdn:js用Date對象處理時間

在工程實踐裏,Date 不是“日期對象”,而是一個“時間點”容器:內部封裝的是自 1970-01-01 00:00:00 <span style="color:red">UTC</span> 起的<span style="color:red">毫秒時間戳</span>(Epoch milliseconds)。(MDN網站)
所以你的策略應該很明確:存儲用時間戳/UTC,展示再按時區格式化。否則“看起來是同一天”,實際上可能是兩個不同時間點,Bug 會悄悄變事故。


1)創建與解析:只信 <span style="color:red">ISO 8601</span>,並明確時區 🧭

// 1. 當前時間點(本機時區環境下的“此刻”)
const now = new Date();

// 2. 通過毫秒時間戳創建(強烈推薦:最穩定)
const d1 = new Date(1700000000000);

// 3. 通過 ISO 8601 字符串創建(推薦:必須帶時區 Z 或 ±hh:mm)
const d2 = new Date("2025-12-31T16:00:00.000Z");
const d3 = new Date("2026-01-01T00:00:00+08:00");

逐行解釋:

  • new Date():取“當前時間點”,但展示會隨運行環境時區變化。
  • new Date(1700000000000):直接指定<span style="color:red">時間戳</span>,跨端一致,是生產最穩輸入。
  • new Date("...Z") / ("...+08:00"):使用標準的<span style="color:red">日期時間字符串格式</span>;實現對標準格式支持最明確。(MDN網站)
  • 非 ISO 的“隨手拼字符串”解析,允許各實現“自由發揮”,你會在不同環境裏收穫不同結果。(MDN網站)

2)取值:本地字段 vs <span style="color:red">UTC字段</span>,別混用 ⚙️

const d = new Date("2026-01-01T00:00:00+08:00");

// 本地時間字段(受運行環境時區影響)
const hLocal = d.getHours();

// UTC 字段(統一口徑,適合日誌/對賬/後端對齊)
const hUtc = d.getUTCHours();

逐行解釋:

  • getHours():拿“本地時區”的小時數,前端展示常用,但跨時區對賬要謹慎。
  • getUTCHours():拿<span style="color:red">UTC</span>口徑,適合做統一計算、寫日誌、做審計。

3)格式化輸出:用 toISOString() 統一,再按業務時區展示 🧾

const d = new Date();
const iso = d.toISOString(); // 永遠是 UTC,並以 Z 結尾

逐行解釋:

  • toISOString():輸出固定形態 YYYY-MM-DDTHH:mm:ss.sssZ,且<span style="color:red">時區永遠是 UTC</span>。(MDN網站)
  • 最佳實踐:接口/數據庫傳輸優先 ISO 或時間戳;頁面展示再“本地化”。

4)時間計算:用毫秒做“硬算”,用 setX 做“日曆算” ⏱️

// 硬算:加 5 分鐘(不關心跨日曆邊界)
const addMinutes = (date, m) => new Date(date.getTime() + m * 60 * 1000);

// 日曆算:加 1 天(關心月份天數變化)
const addDays = (date, days) => {
  const x = new Date(date);
  x.setDate(x.getDate() + days);
  return x;
};

逐行解釋:

  • getTime():把時間點投影為<span style="color:red">毫秒</span>,計算最直接、最可控。
  • setDate/getDate:按“日曆規則”滾動,適合“次日/下月”這類業務語義。
  • 經驗法則:計費/限流窗口/過期時間優先“硬算”;賬期/自然日優先“日曆算”。
    (時間最擅長在你不注意時把邊界條件變成線上工單。)

5)按指定時區展示:用 Intl.DateTimeFormat 做“商業級呈現” 🌍

const d = new Date("2025-12-31T16:00:00.000Z");

const fmt = new Intl.DateTimeFormat("zh-CN", {
  timeZone: "Asia/Shanghai",
  year: "numeric", month: "2-digit", day: "2-digit",
  hour: "2-digit", minute: "2-digit", second: "2-digit",
  hour12: false
});

const text = fmt.format(d);

逐行解釋:

  • Intl.DateTimeFormat:把“同一個時間點”用指定<span style="color:red">時區</span>規則輸出為可讀文本,適合報表、控制枱、客户側展示。
  • timeZone: "Asia/Shanghai":明確展示口徑,避免“部署在哪就顯示哪的時間”的管理風險。
  • hour12: false:企業控制枱更常見的 24 小時制。

分析説明表(拿來就能落地)

業務場景 推薦輸入 推薦存儲 推薦輸出 關鍵風險點
接口傳輸 <span style="color:red">時間戳</span> / ISO(帶Z或偏移) <span style="color:red">UTC</span> 時間戳 ISO(toISOString 字符串解析差異 (MDN網站)
控制枱展示 ISO/時間戳 UTC時間戳 Intl.DateTimeFormat 指定時區 不指定時區=跨地域顯示混亂
過期/限流窗口 時間戳 時間戳 計算結果再格式化 DST/跨時區邊界導致誤差
自然日賬期 ISO/時間戳 UTC + 賬期規則 本地化展示 “日曆算”與“硬算”混用

工作流程圖(推薦團隊統一口徑)

flowchart LR
  A[輸入: 時間戳 / ISO含Z或偏移] --> B[解析為 Date 時間點]
  B --> C[統一存儲: UTC毫秒時間戳]
  C --> D[業務計算: 硬算(毫秒) / 日曆算(setX)]
  D --> E[展示: Intl.DateTimeFormat 指定時區]

前瞻建議:關注 <span style="color:red">Temporal</span>,但短期仍以 Date + Intl 為主 🚀

Date 的痛點在於“時區/日曆/解析”容易混在一起;新一代 Temporal 設計為替代方案,已處於較成熟的提案階段,但在瀏覽器側仍是“並非全量可用”的狀態。(GitHub)
務實打法:現在用 Date + 時間戳 + Intl 立刻把一致性做好,未來再平滑升級到 Temporal,不會推翻現有數據口徑。

如果你把你們業務的三類時間(例如:用户展示時間、計費窗口時間、日誌審計時間)列出來,我可以按“統一口徑 + 數據結構 + 前後端傳輸協議”給你一套可直接納入規範的時間處理標準。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.