逐字段理解 Cron 表达式
理解 Cron 的五个字段、控制范围的运算符、时区陷阱,以及 Unix Cron 与现代变体的差异。
五个字段,一行表达式
经典 Unix Cron 表达式由空格分隔的五个字段组成:分钟(0–59)、小时(0–23)、日(1–31)、月(1–12)、星期(0–7,其中 0 和 7 都表示星期日)。“30 9 * * 1-5”的含义是:第 30 分钟、第 9 小时、每月每天、每月、周一至周五,也就是工作日早上 09:30。
┌ 分钟 (0-59) │ ┌ 小时 (0-23) │ │ ┌ 日 (1-31) │ │ │ ┌ 月 (1-12) │ │ │ │ ┌ 星期 (0-7) │ │ │ │ │ 30 9 * * 1-5
运算符
容易被忽略的是日字段和星期字段的交互:当两者都有限制(都不是 *)时,Cron 通常在任意一个条件匹配时运行,而不是两个条件同时匹配。“0 0 13 * 5”会在每月 13 日以及每个星期五运行,这几乎从来不是作者真正想表达的意思。
- *——字段中的任意值。
- ,——列表:日字段中的 1,15 表示每月 1 日和 15 日。
- -——范围:星期字段中的 1-5 表示周一到周五。
- /——步长:分钟字段中的 */10 表示每 10 分钟;5/20 表示从第 5 分钟开始,每 20 分钟执行一次(5、25、45)。
时区与夏令时
除非实现支持 CRON_TZ 变量或显式时区设置,否则 Cron 会使用系统本地时区。夏令时切换期间,02:30 的任务在秋季可能运行两次,在春季可能一次都不运行。对于计费、报表生成等不能重复执行的任务,应避开 01:00–03:00 时间段,或统一使用 UTC。
Cron 不总是同一种 Cron
五字段格式是 POSIX 经典形式,但不同变体并不完全一致。有些解析器增加开头的秒字段(Quartz、Spring 以及 AWS EventBridge 使用六字段);有些支持名称(JAN、MON)、L(当月最后一天)、W(最近的工作日)和 #(第几个星期几)。Kubernetes CronJob 和 GitHub Actions 使用普通五字段 Cron,但 GitHub Actions 始终按 UTC 执行。
当表达式“在本地有效”却在生产环境表现不同,首先要问的是目标调度器使用哪一种方言。最稳妥的表达式只使用数字和四种基础运算符。
参考资料
相关工具
- Cron 表达式解析器将 Cron 表达式解析为易读说明和下一次执行时间。
- Unix 时间戳转换器在 Unix 时间戳与可读日期之间互相转换。