無需上傳, 100% 本機處理, 無需帳戶

文章

Unix 時間戳記與 cron 表達式詳解

Unix 時間戳記只是一個整數。cron 表達式只是五個欄位。兩者在後端工作中頻繁出現,而且都以可預測的方式讓人出錯:一個因時區,另一個因單位。

什麼是 Unix 時間戳記

Unix 時間戳記計算自 1970-01-01 00:00:00 UTC 以來已過去的秒數,這個參考點稱為 Unix epoch。這個定義有兩個重要後果。第一,計數以 UTC 為基準:數字本身不內嵌時區。1718400000 在地球上任何地方都代表同一個時刻,無論儲存它的機器位於何處。第二,epoch 以秒為單位,而非其他單位。1718400000 這樣的值始終是自 1970 年 1 月 1 日 UTC 午夜起的秒數,除非系統或協議明確做出了不同的選擇。時間戳記在設計上是無時區的,這正是它們在不同地區的時鐘必須明確指代同一時刻的記錄、資料庫和系統間通訊中非常有用的原因。

時間軸顯示左側 1970-01-01 00:00:00 UTC 的 Unix epoch、中間的當前時間戳記,以及右側的 2038 年溢出邊界,標示有號 32 位元整數的最大值。

秒、毫秒與 2038 年問題

許多現代運行環境和 API 使用毫秒而非秒。JavaScript 的 Date.now() 返回毫秒,所以 1718400000000 與秒精度值 1718400000 代表同一個時刻。當你收到一個不熟悉的時間戳記時,數值大小告訴你單位:10 位數的數字幾乎總是秒;13 位數的數字幾乎總是毫秒。2038 年問題源於一個不同的選擇:將秒精度的時間戳記儲存在有號 32 位元整數中。有號 32 位元整數的最大值為 2147483647,對應 2038-01-19 03:14:07 UTC。超過那一秒之後,計數器在沒有處理邊界的系統上溢出為大負數,日期回滾到 1901 年。修復方法是使用 64 位元儲存。目前大多數作業系統和資料庫已經使用,但固定欄位寬度的嵌入式系統、網路設備和幾十年前的舊檔案格式仍存在風險。

將 epoch 換算為人類可讀日期:時區步驟

將 epoch 值換算為可讀日期需要兩個步驟:從整數中取出 UTC 日期元件,然後應用 UTC 偏移以取得本地時間。時間戳記本身是 UTC。當你問 1718325000 代表什麼日期,正確答案是 UTC 的 2024-06-14 00:30。在紐約(夏季 UTC-4),同一秒對應的是前一天晚上,也就是 2024-06-13 的 20:30:改變的不只是時間,日期也變了。這一步驟被跳過時會產生錯誤結果:開發者以 UTC 記錄原始時間戳記,報告工具以本地時間不加換算地呈現,日期看起來相差幾小時或整整一天。Sunasty 的時間戳記換算工具明確處理這一點:你輸入一個 epoch 值,工具會把 UTC 日期時間和你裝置本身的本地日期時間並排顯示,讓這種跨越日期邊界的情況一目了然。換算完全在瀏覽器中運行,你貼上的任何內容都不會被傳送至任何地方。

兩個日曆網格並排顯示同一個 epoch 值:UTC 網格突顯某一天,紐約(UTC-4)網格突顯前一天,呈現時差如何讓當地日期往前推一天。

Cron 語法:五個欄位、範圍、步進和列表

cron 表達式在類 Unix 系統上排程重複性任務。標準語法有五個以空格分隔的欄位:分鐘(0-59)、小時(0-23)、日(1-31)、月(1-12)、星期(0-7,其中 0 和 7 都代表星期日)。欄位中的星號(*)表示「每個有效值」。表達式 30 8 * * 1-5 在星期一至星期五的 08:30 執行。範圍使用連字符:1-5 涵蓋值 1、2、3、4、5。列表使用逗號:1,15 表示第 1 日和第 15 日。步進使用斜線:分鐘欄位中的 */15 表示每 15 分鐘(0、15、30、45)。這些組合子可以一起出現:0-30/10 表示 0、10、20、30。cron 沒有的一個欄位是時區欄位。守護程序讀取其所在機器的時鐘,而機器設定為伺服器的本地時區。若伺服器使用 UTC,但開發者期望本地時間,任務將在錯誤的時鐘時間觸發。實用規則是將 cron 排程視為伺服器本地時間表達式,並在 cron 行旁邊記錄伺服器的時區。

在本地使用時間戳記換算工具

Sunasty 的時間戳記換算工具支援雙向換算:epoch 換算為人類可讀日期,以及人類可讀日期換算回 epoch。你可以輸入秒精度值或毫秒精度值;工具根據數值大小自動偵測單位。工具會把結果以 UTC 和你裝置本身所在的本地時區並排顯示,並附上可直接複製的原始秒數與毫秒數值。「現在」按鈕能一鍵填入目前的時間戳記,是在你不想開啟終端機時快速確認目前 Unix 時間的方法。這裡沒有獨立的時區選擇器:本地欄位永遠反映你瀏覽器目前設定的時區。這些功能都在瀏覽器中運行。你貼入欄位的值由用戶端 JavaScript 讀取,永遠不會離開裝置。

本文涉及的工具

常見問題

為什麼 JavaScript 使用毫秒而非秒?

JavaScript 的 Date 物件從一開始就設計為支援次秒精度,而毫秒的解析度是秒的一千倍,且不需要小數點。代價是數值更大,這就是為什麼 Date.now() 產生 13 位數字,而大多數伺服器端時間戳記是 10 位數。

每個執行 cron 的伺服器都需要使用 UTC 嗎?

不需要,但讓伺服器使用 UTC 是一種常見做法,正是因為它消除了歧義。當伺服器使用 UTC 時,像 0 2 * * * 這樣的 cron 表達式表示 UTC 02:00,而且這個時間全年保持穩定。在觀察日光節約時間的時區伺服器上,同一個任務在夏季和冬季的 UTC 時刻不同,而且在時鐘撥動邊界可能觸發兩次或跳過一次。

2038 年以後時間戳記的安全儲存類型是什麼?

有號 64 位元整數可以儲存秒精度的時間戳記直到西元 292277026596 年,遠超任何實際關切的範疇。目前大多數資料庫預設以 64 位元值儲存時間戳記。若你使用的是使用 32 位元欄位的舊架構或二進位檔案格式,在 2038 年邊界之前遷移至 64 位元儲存是正確的修復方法。