JSON 工具箱

JSON 裡的時間欄位該用什麼格式

結論:時間戳和字串各有取捨,但混用一定出事。建議統一用 ISO 8601 帶時區偏移(或 UTC 的 Z 結尾),儲存用 UTC,展示在前端按使用者時區轉換。

入門約 3 分鐘發佈於 2026-10-30更新於 2026-10-30
JSON 時間欄位的格式選擇與常見坑

結論:時間欄位統一用 ISO 8601 帶時區偏移,伺服器存 UTC 的 Z 結尾格式,前端按使用者時區展示;若選 Unix 時間戳,必須全站統一秒或毫秒並把單位寫進欄位名,純日期不要塞進表示時刻的欄位。

為什麼不能只寫「2026-10-30 14:30:00」

這串文字沒有時區資訊。上海的 14:30 和倫敦的 14:30 相差八小時,程式無法判斷該按哪個解釋。 JavaScript 的 new Date('2026-10-30 14:30:00') 會按執行環境本機時區解析——同一份資料在伺服器和瀏覽器上得到兩個不同的時刻,這類 bug 極難重現。

同理,2026-10-30 這種純日期也不是時刻,它表示「某一天」,用於生日、帳期可以,用於訂單建立時間就丟了精度。

兩種可用格式

A. ISO 8601 字串(推薦)

{
  "createdAt": "2026-10-30T14:30:00+08:00",
  "updatedAt": "2026-10-30T06:30:00Z"
}

優點:人可讀、同格式下可排序、精度可到毫秒、自帶時區。缺點:比時間戳多十幾個位元組。

B. Unix 時間戳(秒或毫秒)

{ "createdAt": 1793519400 }

優點:緊湊、無歧義、跨語言處理簡單。缺點:人不可讀,秒和毫秒極易混用——1793519400 是秒,1793519400000 是毫秒,差三個數量級。

如果選時間戳,必須全站統一單位,並在欄位名上寫清楚:createdAtMs 比 createdAt 安全得多。

具體約定

項 約定
傳輸格式 ISO 8601,帶 Z 或 +08:00
時區 統一 UTC,避免日光節約時間問題
精度 毫秒足夠
欄位命名 createdAt、updatedAt、expiresAt,At 後綴表示時刻
純日期 用 date 型別欄位,如 birthday: "1990-01-01"
時長 用整數 + 單位(timeoutMs: 3000),不要用字串

前端展示

new Intl.DateTimeFormat('zh-TW', {
  dateStyle: 'medium',
  timeStyle: 'short',
  timeZone: 'Asia/Taipei',
}).format(new Date('2026-10-30T06:30:00Z'));

顯式指定 timeZone 比依賴瀏覽器預設值可靠——使用者改了系統時區,展示會跟著變,這在某些場景是期望行為,在報表類場景則不是。

常見坑

坑一:new Date('2026-10-30') 被當成 UTC 零點。 按 ECMAScript 規範,只有日期沒有時間的字串按 UTC 解析;帶時間的按本機時區解析。

坑二:資料庫時區與序列化時區不一致。 MySQL 存 datetime 不帶時區,應用層按本機時間寫入,讀出時又按 UTC 解釋,一來一回差 8 小時。

坑三:日光節約時間。 用本機時間存未來的時刻,遇到切換會出現「這個時間不存在」或「出現兩次」。存 UTC 就沒這個問題。

常見問題

如何在 ISO 8601 與 Unix 時間戳之間選擇?

需要人可讀、可排序、自帶時區時選 ISO 8601 字串,代價是比時間戳多十幾個位元組,解析需要 Date 或 dayjs 之類的函式庫。只追求緊湊、跨語言處理簡單時選時間戳,但必須全站統一秒或毫秒,並在欄位名上標明單位。兩種格式混用會直接製造「同一時刻被解釋成兩個值」的故障。

是否可以把純日期和時刻放在同一個欄位?

不建議。純日期 2026-10-30 表示「某一天」,沒有時刻也沒有時區;表示時刻的欄位則需要精確到時、分甚至毫秒。生日、帳期用 date 型別欄位,建立時間、更新時間用 ISO 8601 的 At 欄位,兩者分開約定。

延伸閱讀