什麼是 Unix 時間戳?
Unix 時間戳是一個單一的數字:從 Unix 紀元(定義為 1970 年 1 月 1 日 00:00:00 UTC)以來所經過的秒數。就是這樣。沒有時區、沒有日期字串、沒有月份名稱——只是一個每秒遞增的整數。
由於紀元是固定且通用的,像 1700000000 這樣的時間戳在地球上的任何地方都代表完全相同的瞬間。東京的伺服器和芝加哥的筆記型電腦都會同意它指的是 2023 年 11 月 14 日 22:13:20 UTC。本地的顯示會因時區而異,但底層的數字永遠不會改變。
一個刻意的簡化:Unix 時間忽略閏秒。它假設每一天都恰好是 86,400 秒,這在天文現實中並不完全正確,但能保持計算的簡潔。下文會詳細說明。
為什麼工程師喜歡它們
時間戳在軟體中無處不在——檔案修改時間、資料庫記錄、API 回應、JWT 過期欄位、日誌行——而且理由充分:
- 它們是單一值。 一個整數儲存了完整的日期和時間。無需解析,沒有
MM/DD與DD/MM的歧義。 - 它們與時區無關。 這個數字始終是 UTC。只有在向人類顯示時才轉換為本地時間。
- 它們可以輕鬆比較和排序。 哪個事件先發生?較小的整數。兩個事件之間的持續時間?將它們相減;答案以秒為單位。
- 它們儲存緊湊。 一個 4 或 8 位元組的整數,相對於格式化字串。
這就是為什麼這麼多基礎設施在底層使用紀元秒數,即使介面顯示的是友善的 2026-07-23。如果你想在兩種表示法之間轉換,Unix 時間戳轉換器 可以進行雙向翻譯。
解讀一個時間戳:實例說明
以時間戳 1000000000 為例——這是一個著名的時間戳,因為它在 Unix 愛好者的電視直播中翻轉。
要手動解讀它,你需要將秒數分解為更大的單位。粗略來說,1,000,000,000 秒大約是 31.7 年(一年約為 31,556,952 秒)。將其加到 1970 年紀元,你會落在 2001 年。精確的時刻是 2001 年 9 月 9 日 01:46:40 UTC。
你很少手動進行這種計算——每種語言都有內建功能。在 Python 中:
```python from datetime import datetime, timezone datetime.fromtimestamp(1000000000, tz=timezone.utc)
2001-09-09 01:46:40+00:00
```
關鍵點:轉換始終錨定於 UTC。該函數透過從紀元向前推進,將原始的秒數轉換為日曆日期。如果你想要本地時間,則在 UTC 轉換之後套用時區偏移——時間戳本身不攜帶任何時區資訊。
2038 年問題
這就是故事變得有趣的地方——也是許多原本設計良好的系統內部存在一個滴答作響的時鐘的地方。
幾十年來,用於保存 Unix 時間的 C 標準類型 time_t 通常是一個有號 32 位元整數。一個有號 32 位元整數可以表示從 −2,147,483,648 到 2,147,483,647 的值。這個上限就是問題所在。
從 1970 年紀元開始計算秒數,值 2,147,483,647 將在 2038 年 1 月 19 日 03:14:07 UTC 達到。一秒鐘後,計數器需要變成 2,147,483,648——但這個數字無法容納在一個有號 32 位元整數中。計數器不會繼續增加,而是會溢位並繞回到最小的負值 −2,147,483,648。
負時間戳被解釋為紀元之前的時間。所以時鐘不僅不會停止——它還會跳回 1901 年 12 月 13 日。任何依賴其 32 位元 time_t 的系統都會突然認為自己身處二十世紀初。
這通常被稱為 Y2K38 錯誤或 Unix 千禧蟲,從結構上講,它與驅動 2000 年恐慌的固定寬度溢位相同——只是時間更遠,根源在於二進位整數的限制,而不是兩位數的年份。
實際影響的地方
現代的 64 位元桌上型電腦和伺服器多年前就已大致修復。風險集中在難以更新的地方:
- 嵌入式與工業系統。 路由器、控制器、醫療設備、汽車 ECU 以及出廠時搭載 32 位元
time_t且可能連續運行 20 年以上未受干擾的 IoT 硬體。許多今天部署的設備在 2038 年仍將繼續服役。 - 舊版 C 程式碼。 針對舊版
time_t定義編譯的應用程式,特別是當該類型滲入磁碟格式或網路協定時。 - 舊版資料庫與檔案系統。 將時間戳打包成 32 位元欄位的儲存格式。一些較舊的系統在處理遙遠的未來日期時已經顯示出症狀——想想一個 20 年的抵押貸款或一個有效期超過 2038 年的憑證。
故障模式並不總是戲劇性的崩潰。有時是一個微妙的錯誤計算日期:一個已過期的令牌被解讀為有效,排序順序顛倒,一個排程工作在 1901 年觸發。
修復方法:64 位元時間
原則上,修復方法很直接——將 time_t 擴展為 64 位元。一個有號 64 位元整數可以計算秒數,遠遠超出任何實際範圍:溢位點大約在未來 2920 億年,舒適地超過了太陽的預期壽命。
大多數現行作業系統已經完成了這項轉變。64 位元 Linux 使用 64 位元的 time_t;即使是 32 位元 Linux 在近年來的核心和 glibc 中也獲得了 64 位元時間支援。困難的部分不在於修復本身——而是在於尋找並重建每一塊仍然假設為 32 位元的韌體、每一種儲存格式以及每一個第三方二進位檔。這項審計工作才是真正的 2038 年專案。
閏秒如何運作
天文時間和原子時間會略微漂移,因此官方 UTC 偶爾會插入一個閏秒,使時鐘與地球自轉保持一致。Unix 時間在設計上假裝它們不存在——它硬編碼了每天 86,400 秒。
當閏秒發生時,系統通常會「抹平」它——將額外的秒數分散到一個時間視窗中(Google 推廣了 24 小時抹平),這樣就沒有時鐘需要顯示不可能的 23:59:60。結果是:Unix 時間戳保持平穩和單調遞增,代價是在抹平期間與嚴格的 UTC 有極小的秒數偏差。對於幾乎所有軟體來說,這正是你想要的權衡。2038 年溢位是一個整數寬度問題;閏秒則是一個獨立的、小得多的定義怪癖——不要將它們混為一談。
關鍵要點
- Unix 時間戳是自 1970 年 1 月 1 日 00:00:00 UTC 以來的秒數,忽略閏秒。
- 它是一個單一的、與時區無關的整數——易於儲存、比較和排序。
- 轉換始終相對於 UTC;本地時間在之後套用。
- 有號 32 位元
time_t將在 2038 年 1 月 19 日 03:14:07 UTC 溢位,繞回為負值並跳到 1901 年。 - 修復方法是 64 位元
time_t;工作重點是審計嵌入式系統和舊版系統。
想親眼看看它的運作嗎?將任何紀元值貼到 Unix 時間戳轉換器 中,將其解讀為人類可讀的日期——或者反過來,將日期轉換為其時間戳。
常見問題
Unix 時間戳是以秒還是毫秒為單位?
經典的 Unix 時間是以秒為單位。然而,JavaScript 和許多 Web API 使用自紀元以來的毫秒,因此像 1700000000000 這樣的值會大 1,000 倍。一個快速判斷方法:近期日期的秒數時間戳有 10 位數;毫秒時間戳則有 13 位。如果不確定,請在轉換前檢查數量級。
2038 年問題會讓我的手機或筆記型電腦當機嗎?
幾乎可以肯定不會。現代的 64 位元作業系統已經使用 64 位元的 time_t,這將溢位推遲到數十億年之後。真正的風險在於長壽命的嵌入式設備和仍然依賴 32 位元時間且可能在 2038 年之前不會更新的舊軟體。
Unix 時間戳可以是負數嗎?
可以。負值代表 1970 年紀元之前的瞬間——例如,-1 是 1969 年 12 月 31 日 23:59:59 UTC。這正是 2038 年 32 位元溢位所產生的結果,這就是為什麼時鐘會看似跳回 1901 年。
為什麼 Unix 時間忽略閏秒?
為了保持計算簡單且可預測。將每一天視為恰好 86,400 秒意味著持續時間只是減法,並且時間戳保持單調遞增。與天文 UTC 的微小不匹配透過「抹平」閏秒來處理,幾乎所有應用程式都更喜歡這種方式,而不是處理 23:59:60 的邊緣情況。
如何在不寫程式碼的情況下轉換時間戳?
使用線上工具。Unix 時間戳轉換器 接受一個紀元值,並立即顯示對應的 UTC 和本地日期時間,它也可以將日曆日期轉換回時間戳。