读懂 cron 表达式:分时日月周五个字段一次讲清
从五个字段、四个特殊字符到每天每周每月的常见写法,把 cron 表达式拆开讲明白,顺带说清最容易翻车的日和周混淆,看完就能反向读懂任何一行 crontab。
读懂 cron 表达式:分时日月周五个字段一次讲清
接手别人留下的服务器,在 /etc/crontab 里看到一行 0 9 * * 1,没有任何注释,心里没底删也不敢删。这是很多人跟 cron 打交道的真实场景。其实 cron 的语法并不复杂,五个字段加四个特殊字符,搞清楚结构以后,再陌生的一行也能读出来。这篇就把它拆开,从字段顺序讲到最坑人的那个细节。
五个字段:分、时、日、月、周
经典的 POSIX cron 一行有五个字段,按空格分开,从左到右依次是:
- 分钟:0 到 59
- 小时:0 到 23,用 24 小时制
- 日:1 到 31,指一个月里的第几天
- 月:1 到 12
- 周:0 到 6,0 和 7 都表示周日
记住顺序是关键,我习惯念成「分时日月周」,五个字念顺了就不会把日和小时写反。比如 30 8 1 1 * 读出来就是:1 月 1 日 8 点 30 分。最后一个字段写成 *,表示「周几都行」,所以这一行只看日期不看星期。
顺便说一句,有些系统会多带一两个字段。开头多一个秒字段就是 6 字段(BusyBox 和部分应用调度器用),末尾多一个年字段就是 7 字段(Quartz / Spring 这套)。判断办法很简单,数空格分出来几个词就是几字段,不用记一堆 flavour 开关。
四个特殊字符:星号、斜杠、逗号、连字符
每个字段里都能用这四个符号,组合出各种节奏:
*星号:任意值。放在分钟位就是每分钟,放在月份位就是每个月。*/N斜杠:每隔 N 个单位。*/15放在分钟位是每 15 分钟。,逗号:列举多个具体值。0,30放在分钟位是每小时的 0 分和 30 分。-连字符:一段连续范围。9-17放在小时位是 9 点到 17 点这一段。
四个符号还能套着用。0-30/5 表示在 0 到 30 这段里每 5 分钟一次,也就是 0、5、10、15、20、25、30 这几个点。范围、步长、列表在五个字段里都能用,熟练以后就像搭积木。
三种最常用的写法
把字段和符号配起来,日常九成的需求就这几种:
- 每天某点:
0 9 * * *,每天上午 9 点整。日、月、周全是*,所以天天跑。 - 每周某天:
0 9 * * 1,每周一上午 9 点。最后一位是 1,锁定星期一。 - 每月某号:
0 9 1 * *,每月 1 号上午 9 点。第三位是 1,锁定每月第一天。
我自己第一次配监控告警时,想要「每 7 分钟跑一次」,顺手写了 */7 * * * *,以为很均匀。后来用解释器看了下命中网格才发现,它在 :00、:07、:14 一路到 :56,然后跳回下一个整点的 :00,中间只隔了 4 分钟。因为 60 除不开 7,每到整点就会漂一下。后来改成 0,15,30,45 * * * *,这才是告警管线真正要的干净节奏。这个教训让我养成习惯:任何 */N 写法,信任它均匀之前先眼见为实。
一个真实例子:0 9 * * 1
拿开头那行举例。0 9 * * 1 拆开看:分钟 0、小时 9、日 *、月 *、周 1。读出来就是「每周一上午 9 点整触发」。如果把它粘进 Cron 表达式解释器,除了这句中英文解释,还能直接看到下 20 次具体触发时间,每行带星期标注,以及一张 24 时 × 60 分的命中热力图。一眼就能确认它是周一的周会提醒,而不是每天都跑的任务。
最容易搞错的:日和周
这是 cron 最大的坑,没有之一。日(第三位)和周(第五位)是两个独立的过滤条件,很多人会把它们混淆。
0 0 * * 1是每周一的 0 点,跟几号无关。0 0 1 * *是每月 1 号的 0 点,跟星期几无关。
更微妙的是:当日和周同时都不是 * 的时候,多数 cron 实现是「或」的关系,而不是「与」。也就是说 0 0 13 * 5 会在「每月 13 号」或者「每个周五」都触发,而不是只在「13 号正好是周五」时触发。这个行为跟直觉相反,踩过一次就再也忘不了。拿不准的时候,把两种写法都粘进解释器对比一下运行列表,比在生产环境上等结果靠谱得多。
还有几个常见的「永远跑不起来」的坑:0 0 31 2 * 要求 2 月 31 日,而 2 月根本没有 31 号,真实 cron 会一整年静默不跑;0 0 30 2 * 只有闰年才触发。这类问题肉眼很难发现,交给工具两秒就能查出来。
收尾
cron 的结构其实很规整:五个字段定位「分时日月周」,四个特殊字符控制节奏,剩下的全是组合。真正需要小心的就是日和周这对容易混的字段,以及 */N 不一定整除的细节。写完一行别急着上线,反向读一遍、看一眼下几次触发时间,基本就能避开大多数事故。如果还要把触发时间换算到别的时区,可以接着用 时区转换器 把第一次触发时间换过去。
Made by Toolora · Updated 2026-06-13