如何逐欄讀懂 cron 表達式
cron 表達式是一行簡短的文字,用來告訴排程器何時執行工作。常見格式有五個欄位,以空格分隔:分鐘、小時、日、月、星期。這一行 0 9 * * 1-5 的意思是週一到週五的 09:00。每個欄位可以是數字、名稱、清單、範圍或間隔,或用 * 代表所有數值。當所有欄位都符合時,工作就會執行。
五個欄位
| 欄位 | 可用數值 | 範例 |
|---|---|---|
| 分鐘 | 0 到 59 | 30 代表每小時的第 30 分鐘 |
| 小時 | 0 到 23 | 9 代表 09:00,採用 24 小時制 |
| 日 | 1 到 31 | 15 代表每月 15 日 |
| 月 | 1 到 12,或 JAN 到 DEC | 3 或 MAR 代表三月 |
| 星期 | 0 到 6,或 SUN 到 SAT | 0 或 SUN 代表星期日,1 代表星期一 |
有些系統也接受 7 代表星期日,但並非所有系統都支援,所以建議使用 0 或 SUN。這種格式的 cron 沒有秒的欄位,因此最小的間隔是一分鐘。
清單、範圍、間隔與名稱
代表該欄位的所有數值。* * * *代表每分鐘執行。- 清單用逗號分隔。
0 9,17 * * *代表每天 09:00 和 17:00 執行。 - 範圍用連字號。星期欄位中的
1-5代表週一到週五。 - 間隔用斜線。分鐘欄位中的
*/15代表 0、15、30 和 45 分。10-30/5代表 10、15、20、25 和 30 分。 - 名稱如
MON-FRI可以取代數字,比較容易閱讀,前提是排程器支援。
這些寫法可以組合。0 8-18/2 * * * 代表從 08:00 到 18:00 之間,每隔兩小時的整點執行。
常見排程
| 表達式 | 意思 |
|---|---|
* * * * * | 每分鐘 |
/15 * * * | 每 15 分鐘 |
0 * * * * | 每小時的第 0 分鐘 |
0 2 * * * | 每天 02:00 |
0 9 * * 1-5 | 週一到週五的 09:00 |
0 9,17 * * * | 每天 09:00 和 17:00 |
30 6 1 * * | 每月 1 日的 06:30 |
0 0 * * 0 | 每週日的午夜 |
0 0 1 1 * | 1 月 1 日的午夜 |
/5 9-17 * 1-5 | 週一到週五,從 09:00 到 17:55 每 5 分鐘一次 |
請注意,0 0 * * 是午夜,0 12 * * 是中午。弄錯小時是最常見的錯誤之一。
日與星期
當「日」和「星期」兩個欄位都有限定時,只要其中任一符合,工作就會執行。這是 Vixie cron 以及許多由它衍生的系統所採用的經典規則。因此 0 0 13 * 5 會在每月 13 日的午夜執行,也會在每個星期五執行。很多人以為只會在「十三日的星期五」執行,結果執行次數比預期多。
如果兩個欄位之一是 *,就只有另一個欄位會生效。若要在星期五且為 13 日時執行,可以為每個星期五排程,並在腳本中檢查日期。其他排程器,包括部分雲端服務,可能採用不同規則,請參閱它們的說明文件。
時區與日光節約時間
cron 依照執行它的機器或服務的時鐘運作,通常就是該機器的當地時區。設定為 02:30 的工作,會在該時鐘的 02:30 執行。請先確認時區(在 Linux 上,執行 date 可以查看)。如果希望工作在各處都依照同一個時鐘執行,許多團隊會把伺服器設為 UTC,部分排程器也允許為每個工作指定時區。
日光節約時間每年會把時鐘調整兩次。春季時,許多地區會從 02:00 直接跳到 03:00,因此設定在 02:30 的工作沒有可執行的時間。秋季時,01:00 到 01:59 這一小時會出現兩次。各排程器對這些情況的處理方式不同:有些會跳過工作,有些只執行一次,有些則執行兩次。如果時間差異對你很重要,請讓工作避開清晨的時間調整區段,或改用 UTC。
六個欄位與 Quartz
有些排程器會在最前面加上秒的欄位,所以 /10 * * * * 代表每 10 秒執行一次。Java 的 Quartz 排程器使用秒、分、時、日、月、星期,以及選填的年份,並另外提供四個特殊字元:
?代表「不指定」。Quartz 要求日或星期其中一個欄位必須使用它,取決於你沒有設定的那一個。L代表最後。日欄位中的L是當月最後一天,星期欄位中的6L是最後一個星期五。W代表最近的工作日。15W是最接近 15 日的工作日,而且不會跨到另一個月。#代表第 n 個星期幾。6#3是第三個星期五。
Quartz 的星期編號與五欄位格式不同。它的 1 是星期日,7 是星期六,所以週一到週五要寫成 2-6,而不是 1-5。複製任何表達式之前,請先確認你的排程器採用哪一種格式。
常見錯誤
- 分鐘欄位使用
*/7。數值會是 0、7、14……直到 56。下一個會是 63,但這個數值不存在,所以 56 之後的執行會落在下一小時的第 0 分鐘。間隔只差四分鐘,而且間距不平均。請使用能整除 60 的間隔,例如 5、10、15 或 30。 - 2 月 30 日。這個日期不存在,所以
0 0 30 2 *永遠不會執行。在只有 30 天的月份使用 31 日也是同樣的情況。依照「任一符合」規則,星期的限定仍可能讓工作在其他日子執行,因此請檢查結果。 - 小時 24 或分鐘 60。這些數值都超出範圍。多數排程器在儲存時就會拒絕,但並非全部都會。
- 以為有秒的欄位。五欄位的表達式只會在整分鐘執行。
- 把 cron 和正規表示式搞混。在 cron 中,
代表所有數值。在正規表示式中,代表重複前一個項目。若要測試模式,請使用正規表示式測試器,並將 cron 表達式分開處理。
檢查接下來的執行時間
在依賴一個排程之前,請先用白話讀出這一行的意思,並列出接下來幾次的執行時間。cron 解讀器可以同時完成這兩件事,是最快找出「任一符合」規則或奇怪間隔的方法。
快速解答
第一個欄位是分鐘還是秒?
在標準的五欄位格式中是分鐘。只有部分六欄位的排程器會加上秒,而且秒會放在最前面。
為什麼我的工作在星期五執行,也會在 13 日執行?
因為日和星期兩個欄位都有設定,所以只要其中一個符合,工作就會執行。如果只想讓其中一個欄位生效,請將另一個欄位設為 *。
cron 使用 UTC 嗎?
只有當機器或服務設定為 UTC 時才是。否則會使用該系統的當地時區。
借助 AI 協助,由英文原文翻譯而成。
留言
還沒有留言,搶先留言吧。


