如何构建 cron 表达式

· 9 分钟阅读

Cron 表达式是在 Linux、云平台、CI/CD 流水线和任务调度器中定义循环计划的标准方式。语法紧凑但不直观,构建一个可视化的 cron 生成器能让你确切看到任务何时运行,在部署前捕获常见错误,并消除自动化中最容易出错部分的猜测。一旦你理解了五个字段、特殊字符和最常见的陷阱,就可以自信地指定任何循环计划。

Cron 简史

最初的 cron 来自 Brian Kernighan,出现在大约 1979 年的 Unix 第七版中。它每分钟重新读取配置并运行所有到期的任务。Paul Vixie 在 1987 年将其改写为现在所称的 Vixie cron,这也是大多数 Linux 发行版至今仍在使用的版本。Vixie cron 加入了按用户的 crontab、环境变量、@reboot 关键字,以及几项让非管理员也能使用该格式的便利功能。

五字段语法在四十多年里几乎没有变化。Amazon EventBridge、Google Cloud Scheduler、Kubernetes CronJob、GitHub Actions、GitLab CI、Jenkins、Airflow、n8n 以及几十个其他系统都消费同样的紧凑格式,只有少量扩展。这种稳定性正是 cron 值得学一次就再也不必重学的原因。这项技能在任何按时钟运行自动化的地方都能转移。

Cron 语法

标准 cron 表达式有 5 个字段,以空格分隔。每个字段控制一段时间,当所有字段都匹配当前时刻时任务运行。

┌───────────── 分钟 (0-59)
│ ┌───────────── 小时 (0-23)
│ │ ┌───────────── 日 (1-31)
│ │ │ ┌───────────── 月 (1-12,或 JAN-DEC)
│ │ │ │ ┌───────────── 星期 (0-6,星期日=0,或 SUN-SAT)
│ │ │ │ │
* * * * *

对小时、分钟和月份,各字段是 AND 关系,但在 Vixie cron 中日和星期是 OR 关系。这意味着 0 12 1 * 1 既在每月 1 日触发,也在每个星期一中午触发,而不仅在恰好是 1 日的星期一。这个陷阱几乎每个人第一次都会中招。

常见 cron 计划

你最常用到的模式:

计划表达式含义
每分钟* * * * *每 60 秒运行
每 5 分钟*/5 * * * *在 :00、:05、:10、:15...
每 15 分钟*/15 * * * *在 :00、:15、:30、:45
每小时0 * * * *每小时整点
每 2 小时0 */2 * * *00:00、02:00、04:00...
每天午夜0 0 * * *每天 00:00 一次
每天上午 9 点0 9 * * *每天 09:00 一次
一天两次0 9,21 * * *09:00 和 21:00
每星期一上午 8 点0 8 * * 1每周一次,星期一
工作日下午 6 点0 18 * * 1-5星期一至星期五
每月 1 日0 0 1 * *每月 1 日午夜
每季度0 0 1 */3 *1 月 1 日、4 月 1 日、7 月 1 日、10 月 1 日
每个工作日早晨0 7 * * 1-5周一至周五 07:00
周日中午0 12 * * 0每周一次,星期日

许多系统也接受展开为等效 5 字段表达式的缩写别名:@yearly@monthly@weekly@daily@hourly@reboot。它们很简洁但并非通用,所以在依赖它们之前请检查你的平台。

如何构建 cron 表达式

  1. 选择粒度:你需要每分钟、每小时、每天一次、每周一次还是每月一次?从满足需求的最粗设置开始。
  2. 使用可视化控件:从下拉菜单中选择分、时、日、月和星期值。或者从预设开始,如「每小时」或「每天午夜」,然后调整。
  3. 预览下次运行时间:生成器显示接下来 5 次执行时间,让你能确认计划在预期的时间触发。
  4. 检查时区:预览应当匹配将运行任务的服务器或调度器的时区,而不是你的本地时间。
  5. 复制表达式并粘贴到你的 crontab、GitHub Actions YAML、AWS EventBridge 规则或任何你使用的调度器中。
  6. 先用短间隔测试,再提交最终计划。一个快速的 */5 * * * * 证明任务会触发;看到两三次执行后,再换成真正的表达式。

特殊字符与运算符

Cron 在任何字段内支持一小套强大的运算符。

字符含义示例
*任意值* * * * * = 每分钟
*/n每 n 个*/15 * * * * = 每 15 分钟
,多个离散值0 8,12,18 * * * = 8 点、中午、18 点
-含端点范围0 9-17 * * * = 9 点到 17 点每小时
n-m/k带步长的范围0 9-17/2 * * * = 9、11、13、15、17
?无特定值(仅 Quartz)0 0 ? * MON(Java 调度器)
L最后(AWS、Quartz)DoM 中的 L = 当月最后一天
W最近的工作日(AWS、Quartz)15W = 离 15 日最近的工作日
#第 n 个星期某(AWS、Quartz)MON#2 = 月度第二个星期一
@hourly简写0 * * * * 相同

原版 Vixie cron 仅支持前五行。高级运算符(LW#?)来自 Quartz,即 Java 的调度库,后被 AWS EventBridge 和少数其他云调度器采用。它们不可移植,所以不要在必须运行于通用 Linux 上的代码中混用。

不同平台上的 cron

Cron 是一族相关的语法,并非单一标准。知道你的调度器讲哪种方言可省下数小时调试。

平台字段备注
Vixie cron (Linux)5经典款。*/n、范围、列表,无高级运算符
BSD cron5类似 Vixie,但环境略有不同
crontab.guru5反映 Vixie 语义的网页解析器
GitHub Actions5Vixie 语法,运行于 UTC,最小 5 分钟精度
GitLab CI5Vixie 语法,运行于实例时区
AWS EventBridge6增加年份。星期使用 1-7(周日=1),支持 L/W/#
Google Cloud Scheduler5Vixie 语法加时区配置
Kubernetes CronJob5Vixie 语法加 @ 简写
Quartz (Java)6 或 7在最前加秒,以及可选的年份
systemd 定时器OnCalendar 格式不是 cron,但用更清晰的语法解决同样的问题

如果你写的计划要在多个平台上运行,坚持使用每个系统都能理解的保守 5 字段子集。只在你确定目标支持时才用 LW#

常见陷阱

cron 的替代品

对某些工作负载,cron 粗到分钟的精度和没有记账机制开始让人难受。最常见的升级:

工具优势何时选用
systemd 定时器清晰的 OnCalendar 语法、跨重启持久、与 unit 集成你已经在用 systemd 并想要更丰富的日志
Anacron休眠后补上错过的执行笔记本或并非始终开机的机器
Airflow / DagsterDAG 依赖、重试、可观测性多步数据流水线
Temporal有状态工作流,正好一次的保证跨服务的长时间编排
AWS EventBridge托管,集成 Lambda、S3、SQSAWS 上的云原生任何任务
GitHub Actions公共仓库免费,运行于托管运行器与 CI 相邻的计划任务
cron 触发的无服务器函数无服务器要维护装得下 Lambda 的轻量任务

对绝大多数一次性循环任务,cron 仍是正确答案。其他工具在你需要状态、重试、依赖或跨机协调时才闪光。

隐私与 cron 生成器

Cron 表达式生成器完全在你的浏览器中运行。你构建的计划、下次运行时间的预览以及复制的表达式从不接触我们的服务器。没有关于生成了哪些表达式的日志,没有关于哪些预设流行的遥测,也没人有办法重建你正在处理的计划。Cron 表达式表面上不是个人数据,但一个任务的计划(每晚数据库导出、每周计费运行、每小时与合作伙伴同步)能透露很多关于一个企业如何运营的信息。把这些信息保留在客户端可以避免把基础设施模式不慎泄露给第三方。对于像选择计划这样的日常任务,默认的隐私级别应当与这些计划所代表内容的敏感度相匹配。

常见问题

cron 表达式的格式是什么?

标准 cron 表达式有 5 个由空格分隔的字段,分别表示分(0-59)、时(0-23)、日(1-31)、月(1-12)和星期几(0-6,其中 0 是周日)。星号(*)表示该字段的「每个」值。

cron 中的 */5 是什么意思?

*/5 语法表示「每 5 个」。在分字段中,*/5 表示每 5 分钟(0、5、10、15…)。在时字段中,*/5 表示每 5 小时。它适用于任意字段。

cron 表达式在所有平台上都相同吗?

5 字段格式在 Linux cron、AWS EventBridge、GitHub Actions 和大多数调度系统上是标准。某些平台会添加第 6 个字段用于秒或年份。请查阅您平台的文档。

如何为每月最后一天安排任务?

标准 cron 没有「最后一天」关键字。可以使用变通方法,如每天运行并在脚本中检查日期,或使用平台特有的扩展(AWS EventBridge 支持 L 表示「last」)。

Why did my cron job not run at the expected time?

The most common cause is timezone confusion. Server cron usually runs in UTC, not your local time. Other causes include the server being asleep at the scheduled minute, the user crontab not being installed, or PATH/environment differences between your shell and cron's stripped-down environment.

What is the difference between 0 in the day-of-week field and 7?

Both 0 and 7 represent Sunday in classic Vixie cron, which uses 0-6 plus an alias for 7. Some implementations (notably AWS EventBridge) use 1-7 with Sunday as 7 and Monday as 1, so always check your platform's documentation before assuming.