什么是 cron 表达式?
cron 表达式是一种紧凑的调度字符串,用于精确告知任务调度器何时触发某个任务。该格式诞生于 1975 年 Unix V7 的 cron 守护进程中,至今几乎没有变化 — 相同的五字段语法如今出现在 Kubernetes CronJob、AWS EventBridge、GitHub Actions 工作流、Google Cloud Scheduler、GitLab CI、Jenkins 流水线以及每个 Linux 发行版仍附带的 crontab 二进制文件中。这套语法将大量含义压缩进十三个左右的字符里,这也正是将其转换为自然语言的解析器在自信部署与凌晨三点回滚之间发挥关键作用的原因。
cron 表达式如何工作?
标准 cron 表达式由五个以空格分隔的字段组成,共同定义一个重复调度。引擎每分钟将当前时钟与表达式进行比对,当所有五个字段都匹配时触发任务。字段从左到右依次为:
- 分钟(0–59)。任务在当前小时的哪一分钟运行。
0表示整点,30表示半点,*/5表示每五分钟(00、05、10……),15,45表示 15 分和 45 分。 - 小时(0–23)。24 小时制的哪个小时。
0为午夜,9为上午 9 点,17为下午 5 点。范围(9-17表示工作时间)和步长值(*/2表示每隔一小时)与分钟字段用法相同。 - 日(1–31)。在一个月的哪一天运行。
1表示每月 1 日,*表示每天,1,15表示 1 日和 15 日。注意31会静默跳过没有 31 天的月份。 - 月(1–12 或 JAN–DEC)。在哪些月份运行。
*表示每月,1,7表示 1 月和 7 月,1-3表示第一季度。三字母月份名称在大多数实现中不区分大小写。 - 星期(0–7,其中 0 和 7 均表示周日)。限定在特定工作日触发。
1-5为周一到周五,0,6为周末,MON-FRI在大多数解析器中有效。当日和星期字段同时被设置为特定值时,经典 cron 在任一匹配时均会触发(逻辑或),这一点总是令人意外。
为什么使用 cron 表达式解析器?
- 在部署前发现静默误读。表达式 `0 2 */3 * *` 是每三天凌晨 2 点触发,而非每三分钟 — 粘贴到这里,您在推送到生产环境前就能用自然语言看清楚。
- 大多数云调度器默认在 UTC 运行。在本地时区预览未来十次执行时间,可在凌晨三点被告警唤醒之前发现夏令时偏差。
- `@daily`、`@weekly`、`@monthly` 等快捷方式方便但含义模糊。解析器会显示底层的五字段形式,让您确切知道调度内容。
- 逐字段构建器让您一列一列地组合调度计划,并实时更新人类可读描述,比第十遍翻阅 cron 手册页快得多。
cron 表达式在哪里使用?
任何需要按时钟重复执行任务的地方都会出现 cron 语法。以下是三个最常见的场景及各自的著名坑点:
- 备份调度。经典的 `crontab -e` 条目,在每晚凌晨 2 点将数据库转储到 S3,或在每月 1 日轮换 `pg_dump` 归档。`0 2 * * * /usr/local/bin/backup.sh` 这一行在无数 Linux 服务器上运行,比 cron 历史上任何其他行都多。把分钟和小时写对,把 stderr 重定向到持久位置,就能用一个自动脚本替代手动检查清单。
- GitHub Actions `schedule` 触发器。`.github/workflows/*.yml` 中的 `on.schedule.cron` 键接受标准五字段 cron,但任务始终在 UTC 运行,且在 runner 队列繁忙时 GitHub 会静默跳过某次触发。常见模式:`cron: '0 9 * * 1-5'` 在 UTC 上午 9 点发送周一至周五的摘要。请先在本地时区预览,避免承诺上午 9 点的摘要实际在 BST 夏令时期间 10 点才到达。
- AWS EventBridge Scheduler。EventBridge cron 表达式新增了年份第六字段,且在日或星期字段中要求用 `?` 代替 `*` — `cron(0 9 ? * MON-FRI *)` 是经典工作日上午 9 点标准 cron 的 EventBridge 译法。用于调度 Lambda 调用、ECS 任务运行和 Step Functions 状态机启动;与经典 cron 语法的不一致是 CloudFormation 部署中 `ValidationException` 错误的头号来源。
真实的 cron 表达式是什么样的?
以 0 9 * * 1-5 为例 — 每个工作日上午 9 点整触发。从左到右逐字段解读:0 是当前小时的第 0 分钟,9 是 24 小时制的上午 9 点,日字段的 * 表示每个日历日,月字段的 * 表示每月,星期字段的 1-5 将触发限定在周一到周五(标准 cron 编号中 1 = 周一)。将其粘贴到上方的输入框,解析器会确认每周一到周五上午 09:00,并在您选择的 IANA 时区下呈现未来十个触发日期。同样的意图在 AWS EventBridge 语法中为 cron(0 9 ? * MON-FRI *) — 注意末尾的年份字段以及标准 cron 用 * 的位置这里用了 ?。同样意图的 Quartz 表达式(六字段,前置秒)为 0 0 9 ? * MON-FRI。三个不同平台,三种不同格式,同一个底层调度。
cron 表达式有且只有一种方式会出错:手误产生一个语法合法却在错误时间触发的调度,而代码审查中没有任何报错可以捕获。读到 `0 0 1 * *` 并知道它是每月 1 日午夜运行而非 1 月 1 日,需要反复练习。上方的解析器将这种练习变成十秒钟的心智检验 — 粘贴表达式,读取自然语言说明,扫描本地时区下的未来十次执行时间,然后满怀信心地提交 YAML,确保 cron 行确实执行了提交信息所描述的内容。
五字段 cron 和六字段 cron 有什么区别?
五字段 cron 是经典 Unix 语法,最小精度为分钟。六字段 cron 在前面新增秒字段,支持亚分钟调度 — Quartz 和 Spring 的 @Scheduled 使用此格式。AWS EventBridge 也使用六字段,但其额外字段是末尾的年份,而非秒。
@hourly、@daily 和 @weekly 是什么意思?
这些是 1987 年 Vixie-cron 引入的昵称。@hourly = 0 * * * *,@daily = 0 0 * * *,@weekly = 0 0 * * 0,@monthly = 0 0 1 * *,@yearly = 0 0 1 1 *。@reboot 在系统启动时执行一次。GitHub Actions 和 EventBridge 不支持这些别名。
cron 中周日是第 0 天还是第 7 天?
在经典 Vixie cron 中,两者都有效 — 0 和 7 均表示周日,这样像 5-7 这样的范围读起来自然地表示周五到周日。周一始终是 1,周六始终是 6。Quartz 和 AWS EventBridge 使用不同的约定:1-7,其中周日为 1。使用前请查阅具体平台文档。
cron 如何处理夏令时?
取决于调度引擎使用的时区。在 UTC(EventBridge、Kubernetes 和 GitHub Actions 的默认时区)下不存在夏令时问题。在本地带夏令时的时区中,经典 Vixie cron 在春季拨快时跳过对应任务,在秋季拨回时执行两次;systemd 定时器则恰好执行一次。