紀元時間詳解:Unix 時間戳零是什麼?

Unix 時間戳 0 是 1970 年 1 月 1 日 00:00:00 UTC。了解為什麼那個日期成為 Unix 紀元、負時間戳代表什麼、紀元的秒/毫秒/微秒有何不同,以及現代系統適用哪些限制。

Unix 時間戳 0 代表什麼

每個 Unix 時間戳都計數自單一參考點——1970 年 1 月 1 日 00:00:00 UTC——以來經過的時間。在 Unix 的原始定義中單位是秒,所以時間戳 0 正好是 1970 年 1 月 1 日的 UTC 午夜,86400 正好是 24 小時之後。現代系統也使用毫秒、微秒與奈秒,但參考點相同。每個正值表示紀元之後的某個瞬間;每個負值表示之前的瞬間。

為什麼是 1970 年 1 月 1 日?

這個日期由貝爾實驗室的 Unix 開發者在 1970 年代初選定,作為略早於 Unix 本身誕生的實用參考點。它需要足夠早,使一般系統時間戳為正;足夠近,以適配早期電腦的小整數範圍;又足夠簡單,便於心算核對。當 Unix 變得有影響力後,語言、作業系統、資料庫、日誌格式與網路協定都繼承了同一個起點。

  • Unix 自 1969 年起在貝爾實驗室開發 —— 紀元設在其稍前
  • 選擇 1 月 1 日作為乾淨的日曆邊界
  • 用 1970 年而非 1969 年,因為實作使用從零開始的計數器
  • 現代所有作業系統、語言與協定都繼承了這個紀元 —— 沒有競爭標準

負時間戳:1970 年之前的日期

負的 Unix 時間戳表示 1970 年 1 月 1 日 00:00:00 UTC 之前的瞬間。大多數現代 64 位系統都能正確支援,這對歷史資料、出生日期、封存記錄,以及與紀元早於 Unix 的系統互通很有用。較舊的函式庫與資料庫可能拒絕負值,因此歷史資料集值得做一次顯式的相容性檢查。

  • -1 = December 31, 1969 23:59:59 UTC (one second before the epoch)
  • -86400 = December 31, 1969 00:00:00 UTC (one day before the epoch)
  • -2208988800 = January 1, 1900 00:00:00 UTC
  • JavaScript: new Date(-86400 * 1000).toISOString() → '1969-12-31T00:00:00.000Z'

格式的實際上限

Unix 紀元本身不是上限;儲存型別才是。儲存在 32 位有號整數中的時間戳,會比儲存在 64 位整數、JavaScript 數字或資料庫原生 timestamp 型別中的時間戳早得多地失效。評估時間戳安全性時,既要問使用什麼單位,也要問用什麼數值型別儲存。

  • 32-bit signed integer max: 2,147,483,647 = January 19, 2038 03:14:07 UTC (the Year 2038 problem)
  • JavaScript Date max: 8,640,000,000,000,000 ms = September 13, 275760 CE
  • 64-bit signed integer max: ~9.2 × 10^18 seconds = year ~292 billion
  • PostgreSQL TIMESTAMPTZ max: January 1, 294276 CE

其他系統的紀元

Unix 並不是運算中使用的唯一紀元。其他系統出於歷史或技術原因定義了自己的參考點。

  • GPS 紀元:1980 年 1 月 6 日 00:00:00 UTC —— 由 GPS 衛星與接收機使用
  • Windows FILETIME:1601 年 1 月 1 日 00:00:00 UTC —— 以 100 奈秒為間隔
  • Apple Cocoa / NSDate:2001 年 1 月 1 日 00:00:00 UTC
  • Excel / Lotus 1-2-3:1900 年 1 月 1 日 —— 為相容 Lotus 而刻意保留的閏年差一錯誤
  • FAT 檔案系統:1980 年 1 月 1 日 00:00:00 本地時間

紀元的秒、毫秒、微秒與奈秒

timestamp 這個詞並不總是表明單位。Unix 秒在作業系統與後端語言中常見。Unix 毫秒在 JavaScript 與瀏覽器 API 中常見。微秒與奈秒出現在資料庫、追蹤系統與高解析度日誌中。單位同時決定精度與你看到的位數。

  • Seconds: 1700000000 — common in Python, PHP, Go, Ruby, C, and Unix command-line tools
  • Milliseconds: 1700000000000 — common in JavaScript Date and many web analytics systems
  • Microseconds: 1700000000000000 — common in some databases and event pipelines
  • Nanoseconds: 1700000000000000000 — common in high-resolution tracing and systems languages
  • Always document the unit when storing epoch values in APIs, CSV files, and database columns

紀元時間 vs UTC vs 本地時間

紀元時間是一個計數。UTC 是定義參考時刻的全球時間標準。本地時間是基於 America/New_York 或 Asia/Tokyo 這類時區的顯示選擇。Unix 時間戳不會因使用者出行而改變;改變的只是格式化的日曆日期與時間。

  • 同一個時間戳在不同時區可能顯示為不同的本地日期
  • UTC 輸出最適合日誌、API 與跨伺服器偵錯
  • 本地輸出最適合日曆、使用者介面與報表
  • 時區偏移在格式化時套用,並不儲存在 Unix 時間戳內部

紀元時間常見問題

紀元時間總是以秒計嗎?
經典的 Unix 時間戳是自 1970-01-01 00:00:00 UTC 起的秒,但許多系統在同一紀元下使用毫秒、微秒或奈秒。
Unix 時間戳能表示 1970 年之前的日期嗎?
可以。負時間戳表示 Unix 紀元之前的日期,不過較舊的函式庫與資料庫可能不支援。
Unix 時間戳包含時區嗎?
不包含。Unix 時間戳表示 UTC 中的一個瞬間。只有在把該瞬間轉換為可讀的本地日期時才會使用時區資訊。
Unix 時間戳的最大值是多少?
取決於儲存型別,而非紀元。32 位有號整數最大為 2,147,483,647(2038 年 1 月 19 日),而 64 位整數或 JavaScript 數字可達數億年。詳情見 2038 年問題。