cron 表達式產生器與解析器

*/15minute
*hour
*day of month
*month
*day of week

預設

下次執行

本地時間
@yearly · @annually · @monthly · @weekly

您輸入的內容不會被儲存、記錄或分享。

輸入 cron 表達式,即可看到實際的下次執行時間。每個欄位都會驗證,永遠不會觸發的排程也會標示出來。

使用方式

  1. 輸入表達式,或從預設值開始。
  2. 五個欄位的意義會標示在下方。
  3. 部署前先確認下次執行時間。

五個欄位

標準的 cron 運算式由空格分隔的五個欄位組成:分鐘 0-59、小時 0-23、日期 1-31、月份 1-12,以及星期 0-7,其中 0 和 7 都代表星期日。月份與星期也可以寫成三個字母的英文名稱。

每個欄位都支援同樣的四種寫法。星號符合所有值。以逗號分隔的清單符合其中任一值。以連字號表示的範圍符合其間的所有值。以斜線表示的間隔會從範圍中每隔 n 個取一個值,所以分鐘欄位的 */15 代表每十五分鐘,0-30/10 則代表第 0、10、20、30 分鐘。

@hourly、@daily、@weekly、@monthly 與 @yearly 這些簡寫會展開成對應的運算式,適用時值得使用,因為它們不可能被讀錯。

日期與星期的規則

這是 cron 行為中幾乎每個人都會踩到的一點,而且是規格明訂,並非意外。當日期與星期兩個欄位都有限制(都不是星號)時,兩者是以 OR 而非 AND 組合。

所以 0 0 1 * MON 的意思並不是「剛好是星期一的每月一日」,而是每個月的一日,再加上每個星期一。如果只要星期一,日期欄位必須是星號;如果只要每月一日,星期欄位必須是星號。五欄位運算式沒有標準方式可以表達兩者的交集,常見的變通做法是排程兩者的聯集,再在工作本身裡檢查日期。

下次執行時間正是為了抓出這種情況而存在的。讀欄位只能知道你寫了什麼;讀日期才能知道實際會發生什麼。

時區與日光節約時間

這裡顯示的執行時間採用你瀏覽器的時區。實際執行工作的伺服器有自己的時區,而且常常是 UTC,兩者之間的落差是工作在錯誤時間觸發的常見原因。在相信確切時間之前,請先確認伺服器設定或排程器的時區欄位。

日光節約時間則更加棘手。在實施日光節約的時區,排定在 02:30 的工作,在時鐘撥快的那天早上根本不會執行,因為那個時間不存在;在時鐘撥回的那天早上則會執行兩次。任何漏跑或重複執行會造成問題的工作,例如計費、對帳、寄送郵件,都應該以 UTC 排程,或避開轉換發生的凌晨一點到三點。

不同實作對機器睡眠或關機期間錯過的工作處理方式也不一致。有些直接略過,有些在喚醒時執行,有些則會把每一次錯過的執行一口氣補跑完。

你會在其他地方遇到的擴充

五個欄位是標準格式,Linux 的 cron、Kubernetes CronJob 與多數託管排程器接受的都是它。有幾個廣泛使用的系統對它做了擴充,在它們之間複製運算式不一定能直接沿用。

Quartz,以及採用它的 Spring 排程器,使用六或七個欄位:在最前面加上秒,最後加上可選的年份。所以貼進去的五欄位運算式會被整體錯位一格解讀,結果不是報錯,而是在錯誤的時間執行。Quartz 還增加了代表最後的 L、代表最接近平日的 W,以及代表當月第 n 個星期幾的 #。Linux 上標準的 Vixie cron 增加了 @reboot。AWS EventBridge 使用六個欄位,並要求兩個日期相關欄位中恰好有一個是問號而不是星號。

本工具驗證並解說的是五欄位標準格式。如果你的排程器屬於上述之一,在假設運算式在那裡意義相同之前,請先查閱它的文件。

cron 工作真正執行時的環境

排程工作失敗的原因,出在環境的遠比出在排程寫法的多。cron 不會載入你的 shell 設定檔,所以 PATH 非常精簡,往往只有 /usr/bin 和 /bin,於是在終端機裡跑得好好的指令,到了這裡就變成 command not found。可靠的習慣是替直譯器和腳本都寫上絕對路徑,或是在 crontab 最上方明確設定 PATH。

工作目錄是使用者的家目錄而不是專案目錄,所以相對路徑會解析到意想不到的地方。登入 shell 設定的環境變數統統不存在,包括任何透過 shell hook 載入的 .env 內容。此外,百分號在 crontab 裡有特殊意義:它會被轉換成換行符號,這正是像 %Y 這種日期格式字串若沒有跳脫,就會悄悄弄壞整條指令的原因。

另一半問題出在輸出。工作寫到 stdout 或 stderr 的內容,若系統上有郵件傳送代理就會寄給擁有者,沒有就直接丟棄,這就是工作能默默失敗好幾個月的原因。請把輸出導向一個你真的會去看的記錄檔,或是讓工作在成功與失敗時都主動回報給你的監控系統。

重疊執行、冪等性,以及錯過的那一次

不管上一次執行結束了沒有,cron 都會照著排程再啟動一次。一個要跑五分鐘的工作配上五分鐘的排程,遲早會有兩份同時在跑,接著變成三份,而故障通常是以重複處理或死結的形式浮現,而不是以排程錯誤的形式。標準解法是上鎖:Linux 上的 flock、資料庫的 advisory lock,或共用儲存區裡的租約;而且它必須有逾時機制,否則一次當掉的執行會把之後每一次都擋住。

請把每個工作設計成跑兩次也無害。實務上這通常表示要記錄處理過什麼,而不是假設排程本身就定義了處理範圍:挑出還沒處理的資料列、標記它們,讓第二次執行找不到事情可做。

反過來的問題是錯過的那一次。如果機器在睡眠或行程掛了,有些實作會跳過那一次,有些會延後補跑,有些則會把錯過的每一次一口氣全部跑完。Anacron 的存在就是專門為了處理不會全天開機的機器,而容器排程器也各有自己的政策,在依賴它之前值得先讀清楚。

crontab 之外的現代選擇

在目前多數 Linux 發行版上,systemd timer 已經取代了 cron,並提供 cron 從來沒有的功能:相依順序、資源限制、自動寫入 journal 的記錄、避免同時湧入的隨機延遲,以及 Persistent=true,讓錯過的執行在下次開機時補跑。代價是設定變多,因為一個 timer 加一個 service unit 是兩個檔案,而不是一行文字。

Kubernetes CronJob 沿用同樣的五欄位語法,再加上並行政策、歷史保留數量與截止期限處理,而這恰好就是把上面談到的那一組問題明確攤開來處理。託管型排程服務,例如雲端事件匯流排、CI 排程、無伺服器計時器,通常保證的是至少一次送達而非恰好一次,這又把冪等性的責任推回到工作本身。

如果是應用程式內部的工作,搭配延遲訊息的佇列往往比任何排程器都更合適,因為重試、可見性與監控都是佇列本來就有的,而不是事後硬接上去的。

大家實際會寫的排程

每十五分鐘是 */15 * * * *。每天凌晨 02:30 是 30 2 * * *。平日 09:00 是 0 9 * * 1-5。每月一號的午夜是 0 0 1 * *;至於「每月最後一天」根本沒有標準寫法,常見的變通做法是每天都跑,然後在明天不是一號時直接結束。

有兩個習慣能讓 crontab 日後還讀得懂。第一,把負載錯開,不要把所有東西都排在整點:7 3 * * * 並不比 0 3 * * * 難寫,卻能避開機器上其他所有工作的競爭。第二,替每一行註明它做什麼、由誰負責,因為 crontab 活得比當初加上那一行的人的記憶還久。

遇到真的很複雜的排程,把它拆成兩條簡單的設定,通常比寫一條聰明的運算式清楚得多;而當一個安靜跑了一整年的工作突然罷工、你在凌晨三點被叫起來時,你要的正是這份清楚。

怎麼知道工作到底有沒有跑

排程工作最典型的失敗形式是沉默。轟轟烈烈失敗的工作當天就會被修好;停止執行的工作則什麼輸出都沒有,直到它產生的週報連續第三週沒出現,才有人注意到。

解決這件事的模式叫做 dead man's switch 監控:工作成功時對監控服務送出一次 ping,服務若在預期的時間窗內沒收到 ping 就發出告警。這等於把告警的方向反過來,而且能抓到所有情況:主機當機、crontab 被刪掉、部署失敗、重開機後再也沒回來的機器,因為從外面看,這些狀況長得一模一樣,都是什麼事都沒發生。

要記錄的是這一次執行做了什麼,而不只是它跑過了。一行寫上開始時間、結束時間、處理筆數與結束狀態,就能把模糊的懷疑變成明確的答案,這也是「知道工作有跑」與「知道工作有用」之間的差別。當一個夜間工作連續一個月默默處理了零筆資料時,記錄裡的筆數通常是唯一能指出它從哪天開始出問題的證據。

常見問題

為什麼要顯示下次執行時間,而不只是文字說明?
因為一個表達式可能語法完全正確,卻不是您想表達的意思。讀那五個欄位只能知道您寫了什麼;看接下來六次的日期才知道實際會發生什麼。排程的錯誤多半就是在這個差異中被發現的。
同時指定「日」與「星期」會怎樣?
兩者是以 OR 而非 AND 結合。因此「0 0 1 * MON」會在每月 1 號「以及」每個星期一執行,而不是只在剛好是 1 號的星期一。幾乎所有人都會誤解,但這是規格定義的行為,看下次執行時間就一目了然。
支援哪些 cron 語法?
標準五欄位:分、時、日、月、星期。支援萬用字元、範圍、清單、間隔、月份與星期的三字母縮寫,以及 @daily、@hourly、@weekly、@monthly、@yearly 等簡寫。星期日可寫成 0 或 7。
顯示的時間是哪個時區?
您瀏覽器的時區。伺服器上的 cron 使用該伺服器的時區,通常是 UTC,往往與您電腦顯示的不同,因此若需精確到小時,請先確認伺服器設定。
為什麼會顯示某個表達式永遠不會執行?
因為有些組合根本不可能成立,例如 2 月 30 日。工具會直接說明,而不是顯示一個空清單。

最後更新:

回報問題

請提供操作步驟、預期結果及實際結果。請移除機密與個人資料。

相關工具