Cron 表达式速查与避坑指南
定时任务写错一次,轻则没跑成,重则半夜把服务打挂。这篇把五字段语义、常用表达式和特殊字符整理成速查表,再逐个拆解让任务翻车的经典坑,附上验证方法。
五个字段各管什么
标准 cron 表达式由 5 个字段组成,用空格分隔,依次是分、时、日、月、周。站内 Cron 表达式生成器就按这套规则解析,输入即给出中英文解释和接下来 5 次执行时间,改一个字符立刻重算。
| 字段 | 取值范围 | 支持写法 | 示例 |
|---|---|---|---|
| 分 | 0 到 59 | 数字、逗号列表、区间、步进 | 0,30。 |
| 时 | 0 到 23 | 同上,区间支持回绕 | */6。 |
| 日 | 1 到 31 | 可用问号代替星号 | 1,15。 |
| 月 | 1 到 12 | 数字或 jan 到 dec 缩写 | 1,4,7,10。 |
| 周 | 0 到 7 | 0 和 7 都表示周日,缩写 sun 到 sat | 1-5。 |
三点补充。输入不限大小写,MON 和 mon 都认。周字段写 7 会被归到周日,等价于 0。问号只在日和周两个字段里有效,写到分或时里会直接报错。字段数必须正好 5 个,多一个少一个都不行,空格可以连续多个。
月和周的英文缩写来自英文月名与星期名的前三个字母。jan 是一月,dec 是十二月,sat 是周六。写数字最稳妥,缩写适合从别人博客抄来的表达式对不上号时对照用。
把字段想成时间的三层过滤更容易记住。月先筛掉大部分日子,日和周再筛掉剩余日子里的绝大多数,最后分和时决定当天哪一分钟动手。写表达式时按这个顺序推一遍,命中逻辑就不容易绕晕。备份类任务挑业务低峰,清理类任务错开备份,重活别挤在同一个整点。
常用示例速查表
下表 14 条覆盖大部分日常场景。前六条与站内生成器的常用预设一致,粘进工具即可看到解释与执行时间预演。
| 表达式 | 含义 |
|---|---|
| * * * * * | 每分钟执行一次。 |
| 7 * * * * | 每小时第 7 分执行一次。 |
| 0 * * * * | 每小时整点执行。 |
| 30 8 * * * | 每天 08:30。 |
| 0 9 * * 1-5 | 工作日 09:00。 |
| 0 10 * * 6 | 每周六 10:00。 |
| 30 8,20 * * * | 每天 08:30 与 20:30 各一次。 |
| 0 */6 * * * | 每 6 小时,落在 0、6、12、18 点。 |
| */15 * * * * | 每 15 分钟一次。 |
| 0 9 1 * * | 每月 1 号 09:00。 |
| 0 9 1,15 * * | 每月 1 号与 15 号 09:00。 |
| 0 9 1 1,4,7,10 * | 每季度首月 1 号 09:00。 |
| 0 9 1 1 * | 每年 1 月 1 号 09:00。 |
| 0 22-2 * * * | 每天 22 点到次日 2 点整点,区间回绕写法。 |
季度任务写 1,4,7,10 最直观。月域 1/3 在本工具里等价于 1,4,7,10,但数字加步进不是所有实现都认,跨环境使用前先验证。每年一次的任务写死月和日,别依赖月末相关写法。
在站内工具里验证的流程
速查表给了起点,验证靠工具。流程四步,两分钟内能走完。
- 把表达式粘进输入框,先读中英文解释,看语义和你想的是否一致。
- 看"接下来 5 次执行时间",核对日期、星期与时刻。
- 拿不准某个字段,点字段输入框下方的快捷按钮,或直接改单字段,预演会跟着变。
- 确认无误后复制表达式,粘贴到部署目标,别手抄,抄错一个字符全盘皆错。
涉及日周同限的写法,工具会专门给出提示,预演日期里也能看出"或"的痕迹。执行时间预演按你设备的本地时钟计算,与服务器时区不一致时,以服务器时区为准再换算一次。
常见错误写法对照
下面这些写法都见过真实案例,逐条给出问题所在。
| 写法 | 问题 |
|---|---|
| 60 0 * * * | 分钟超出 0 到 59,直接报错。 |
| 0 9 * * 8 | 周字段超出 0 到 7,直接报错。 |
| 0 0 31 2 * | 2 月没有 31 号,永远不会执行。 |
| 0 ? * * * | 问号写进了时域,问号只允许出现在日和周。 |
| * * * * | 只有 4 个字段,字段数必须正好 5。 |
| @hourly | 站内工具不支持简写,请展开成 0 * * * *。 |
选型时先想清执行频率的上限。心跳与监控类可以放宽到每分钟,报表类按小时或按天,账务类按月固定日。频率越高,任务本身越要轻,重任务密集调度会把机器压垮。写进表达式之前,把"什么时候该跑、不该跑"一句话说清,再翻译成五个字段。
特殊字符与简写
符号写法决定命中哪些时刻。下表逐个说明,并标注站内工具是否支持。
| 写法 | 含义 | 站内工具 |
|---|---|---|
| * | 匹配字段内所有值。 | 支持。 |
| , | 列表,各值取并集。 | 支持。 |
| - | 闭区间;小时域支持跨零点回绕,如 22-2。 | 支持。 |
| / | 步进。星号加步进从字段最小值起算,数字加步进从该数字起算到字段最大值。 | 支持。 |
| ? | 占位符,等价于星号,仅日和周字段可用。 | 支持。 |
| 缩写 | 月支持 jan 到 dec,周支持 sun 到 sat。 | 支持。 |
| L | 表示本月最后一天,或倒数第几个周几。 | 不支持,需在目标环境验证。 |
| W | 表示离指定日最近的可用工作日。 | 不支持,需在目标环境验证。 |
| # | 表示当月第几个周几,如 5#3。 | 不支持,需在目标环境验证。 |
| @简写 | @daily、@weekly、@monthly、@reboot 一类简写。 | 不支持,需在目标环境验证。 |
站内工具只接受 5 个空格分隔的字段,@daily 会被判成字段数错误。想表达每天零点,直接写 0 0 * * *。L、W、# 是各家实现的扩展,cronie、systemd timer 和各类云调度器行为不一。用之前先查目标环境的文档,或在测试环境跑一轮,确认命中时间符合预期再上生产。
避坑:六个最容易翻车的地方
日周同限是或不是且
0 0 1 * 1 常被当成"每月 1 号且逢周一"。实际语义是"每月 1 号或每个周一"。日和周两个字段同时给出限制时,命中任意一个就执行,这是标准 cron 的规则。站内工具检测到这种写法会给出提示,预演里也会露馅:执行日期明显多于每月一天。只想按日期跑,周域写星号。只想按星期跑,日域写星号或问号。
月末 31 号陷阱
0 0 31 * * 想表达每月最后一天,实际只在有 31 号的月份执行。2 月永远没有 31 号,4、6、9、11 月只有 30 天,任务整月静默,而且没有任何报错。这种错误最难发现,因为任务在别的月份明明跑得好好的。站内工具不支持 L 写法,无法直接表达"本月最后一天"。常见替代方案是每天跑一次脚本,脚本里判断明天是不是 1 号,是再干活。这个方案不依赖扩展语法,跨环境通用。
时区:表达式里没有时区字段
cron 的五个字段只描述钟面时间,不描述时区。同一串 0 9 * * *,在北京时间的机器上是本地九点,在 UTC 的服务器上就是 UTC 九点,差出八小时。服务器默认时区常为 UTC,云主机也多如此。部署前先跑 date 命令看服务器时区,再决定字段怎么填。站内工具按你设备的本地时间演算执行时刻,与服务器时区可能不同,跨环境迁移时留意这层差异。
容器与函数计算环境还要多看一层。容器内的时区常取决于镜像设置,镜像默认 UTC,装了时区包才会跟随宿主。有些实现提供 CRON_TZ 或时区后缀一类的扩展,属于非标准能力,先确认目标环境是否支持再依赖。最稳的做法是把服务器时区、表达式语义、预期时刻三者在纸上对一遍。
夏令时跳变
实行夏令时的时区,每年有两次异常。春季时钟拨快一小时,凌晨某些钟面时刻当天不存在,恰好排在这些时刻的任务当天不会触发。秋季时钟拨回,同一钟面时刻出现两次,按钟面匹配的任务当天可能跑两次。UTC 没有夏令时,服务器统一用 UTC 能绕开大部分问题。坚持用本地时区的,跳变日前后多看一眼日志,确认任务执行次数符合预期。
步进从哪个值起步
星号加步进从字段最小值开始。分钟 */5 命中 0、5、10 直到 55,不是从部署任务那一刻对齐。月域 */3 命中 1、4、7、10,正好对应四个季度的首月。数字加步进从该数字开始:小时 9/2 命中 9、11、13 直到 23。想要整点起每 30 分钟一次,写 0/30 或 0,30 都行,写 5/30 就会从第 5 分钟开始。部署完看一遍执行记录,就能确认起步点对不对。
列表与步进可以混用,分钟写 0,10-30/10 会命中 0、10、20、30。动笔前先想想是否值得,能拆成两条简单表达式就拆,半年后读配置的人会感谢你。
区间回绕并非到处通用
小时域写 22-2,站内工具会命中 22、23、0、1、2,跨零点的值班任务很好用。但不少经典实现只支持从小到大的区间,把 22-2 当空集或直接报错。这类差异不会写在文档第一页。把表达式迁去新环境时,先用"下一次执行时间"预演验证,再上生产。
上线前的三个动作
第一,把表达式粘进站内生成器,读一遍中英文解释,确认语义与预期一致。第二,看接下来 5 次执行时间,重点核对日期与星期,尤其涉及日周同写的时候。第三,上生产后第一周盯日志,核对实际执行次数与时刻。三步都过,这串表达式才算可信。改表达式和改代码一样,都要留验证痕迹。
把最终表达式连同服务器时区一起写进部署文档,注明语义与验证日期。半年后接手的人不需要重新推导你的意图。这条习惯比任何速查表都管用。