cron 是類 Unix 系統排定重複性工作的方式,它的表達式格式遠不只用在 crontab——CI 流程、Kubernetes CronJob、各種雲端排程都用它。語法乍看很神祕,其實就是用空白隔開的五個欄位。
最常見的那個排程,我們的工具怎麼讀它。 在 cron 產生器輸入
0 9 * * 1-5,它會把每個欄位念回來:Minute: 0 Hour: 9 Day of month: every Month: every Day of week: Mon-Fri這裡看得到兩個最常讓人踩坑的地方。「日」與「星期」都是
every,而當兩者都不設限時,排程就是每天跑 —— 但如果兩個都設了限制,它們的行為是 OR 而不是 AND,那是 cron 最常見的 bug。另外1-5是週一到週五,因為一週從 0 = 星期日開始算。
五個欄位
┌── 分 (0–59)
│ ┌── 時 (0–23)
│ │ ┌── 日 (1–31)
│ │ │ ┌── 月 (1–12)
│ │ │ │ ┌── 星期 (0–7,0 與 7 都是星期日)
│ │ │ │ │
* * * * *
每個欄位回答「在哪些值執行?」* 代表「每一個」。所以 * * * * * 是每一分鐘都執行。
欄位內的語法
*——每一個值。5——剛好是 5。1-5——範圍,1 到 5。*/15——間隔:每 15 個(0、15、30、45)。1,15,30——特定值的清單。- 名稱——月份用
JAN–DEC,星期用SUN–SAT。
可直接套用的範例
| 表達式 | 意思 |
|---|---|
* * * * * | 每分鐘 |
*/5 * * * * | 每 5 分鐘 |
0 * * * * | 每小時整點 |
0 9 * * * | 每天 09:00 |
0 9 * * 1-5 | 週一至週五 09:00 |
0 0 * * 0 | 每週日午夜 |
0 0 1 * * | 每月 1 號 |
30 3 1 1 * | 1 月 1 日 03:30 |
下面每一條「人話」都是我們自己的 cron 產生器吐出來的 —— 它把五個欄位解析出來再用文字唸回去,這是抓「欄位數錯位」最快的方法。
| 運算式 | 我們的工具讀成 |
|---|---|
* * * * * | 分: 每個 時: 每個 日: 每個 月: 每個 星期: 每個 |
*/15 * * * * | 分: 每 15 個 時: 每個 日: 每個 月: 每個 星期: 每個 |
0 * * * * | 分: 0 時: 每個 日: 每個 月: 每個 星期: 每個 |
0 9 * * 1-5 | 分: 0 時: 9 日: 每個 月: 每個 星期: 一-五 |
30 3 * * 0 | 分: 30 時: 3 日: 每個 月: 每個 星期: 日 |
0 0 1 * * | 分: 0 時: 0 日: 1 月: 每個 星期: 每個 |
0 0 * * 1 | 分: 0 時: 0 日: 每個 月: 每個 星期: 一 |
0 */2 * * * | 分: 0 時: 每 2 個 日: 每個 月: 每個 星期: 每個 |
唯一的陷阱:日 vs 星期
如果「日」和「星期」兩個欄位都有限定(不是 *),cron 會在任一符合時執行——不是兩個都要符合。所以 0 0 13 * 5 會在每月 13 號以及每個星期五執行,而不是只在「13 號星期五」。不確定時,就用實際執行時間來驗證。
最容易讓人絆倒的兩條運算式只差一個字元。0 0 1 * * 讀成 分: 0 時: 0 日: 1 月: 每個 星期: 每個 —— 每個月的第一天。0 0 * * 1 讀成 分: 0 時: 0 日: 每個 月: 每個 星期: 一 —— 每個星期一。第 3 欄是「日」、第 5 欄是「星期」;在多數實作裡兩個同時設定是 OR 而不是 AND,所以 0 0 1 * 1 會在每月 1 號以及每個星期一都跑。
上線前先驗證
最保險的做法,是先看它「實際會在哪些時間點觸發」。Cron 表達式產生器會用白話說明每個欄位,並列出你本機時區的下次執行時間,還有一鍵範本。全程在你的瀏覽器本機執行。
相關工具
- 也在處理 Unix 時間戳?用時間戳轉換工具。
快捷字串
多數 cron 服務都接受用具名快捷字串取代那五個欄位:
| 快捷字串 | 等同於 | 何時執行 |
|---|---|---|
@yearly(或 @annually) | 0 0 1 1 * | 每年一次,1 月 1 日 |
@monthly | 0 0 1 * * | 每月 1 號 |
@weekly | 0 0 * * 0 | 每週日 |
@daily(或 @midnight) | 0 0 * * * | 每天午夜 |
@hourly | 0 * * * * | 每小時 |
@reboot | —— | 開機時一次 |
也要留意欄位數量的差異:Spring 的 @Scheduled、Quartz,以及部分雲端排程會在最前面多一個秒欄位(共六欄);AWS EventBridge 則用六欄格式,且禁止同時指定「日」與「星期」。把五欄表達式貼進六欄的解析器,整串就會錯開一欄。
時區與日光節約時間
傳統 crontab 沒有時區欄位——它是以服務所在機器的本地時間觸發。在 Linux 上,你可以在檔案裡加一行 CRON_TZ=UTC(或 TZ)來覆寫;多數雲端排程則是提供一個時區下拉選單。凡是跨區域共用的排程,用 UTC 最保險,誰都不必再心算時差。
日光節約時間的切換是經典陷阱。時鐘往前撥時,落在被跳過那一小時內的工作(例如 30 2 * * *)當天可能不會執行;往回撥時,落在重複那一小時的工作則可能跑兩次。把重要工作排在 01:00–03:00 之外,或直接用 UTC。如果你同時也在處理 epoch 時間,Unix 時間戳完整教學說明了它們怎麼對應到牆上時鐘的時間。
快速 FAQ
- 範圍和間隔能一起用嗎? 可以——
0-30/10代表 0、10、20、30。 - 「時」欄位裡的
*/2是什麼意思? 每隔一小時:0、2、4⋯22。 - cron 會補跑錯過的排程嗎? 不會。若排定時間點機器是關的,單純的 cron 就直接略過——需要補跑請用
anacron。