跳到主要内容
LeedyBox
支持我们

如何读懂 cron 表达式

cron 表达式用几个以空格分隔的字段描述重复执行的计划。思路很简单,但不同系统的字段顺序和特殊字符各不相同。本指南介绍如何解读常见的格式。

Unix 的五个字段

经典的 Unix 和 Linux cron 使用五个字段,从左到右依次为:

分 时 日 月 星期

因此 30 9 * * 1-5 的意思是“周一至周五的 09:30”。分钟的取值为 0 到 59,小时为 0 到 23,日为 1 到 31,月为 1 到 12。星期的取值为 0 到 6,0 表示星期日(许多实现也接受用 7 表示星期日)。大多数版本还接受 JAN 或 MON 这样的名称,以及 @daily 或 @hourly 这样的宏。

Spring、Quartz 和 AWS 格式

其他调度器增加了字段,这是把表达式从一个系统复制到另一个系统时最常见的混淆来源。

格式 字段 星期
Unix / Linux 5 个:分 时 日 月 星期 0–6,星期日 = 0
Spring 6 个:秒 分 时 日 月 星期 0–7,星期日 = 0 或 7
Quartz 6 或 7 个:秒 分 时 日 月 星期 [年] 1–7,星期日 = 1
AWS EventBridge 6 个:分 时 日 月 星期 年 1–7,星期日 = 1

同样的数字可能有不同的含义:0 0 12 * * ? 在 Quartz 中表示“每天中午”,而按 5 个字段解读则是无效的。星期的编号也会错位:在 Quartz 和 AWS 中 2 表示星期一,而在 Unix cron 中表示星期二。在支持的地方,使用 MON 这样的星期名称可以避免这种歧义。

特殊字符

  • * 字段的所有值。
  • , 值列表,例如 1,15。
  • - 范围,例如 9-17 或 MON-FRI。
  • / 步长:分钟字段中的 */15 表示每 15 分钟;5/15 表示从 5 开始(经典 Unix cron 不支持,需改用 5-59/15 这样的范围)。
  • ? “不指定值”;Quartz 和 AWS 要求在日或星期字段中使用它。
  • L 最后:日字段中的 L 表示当月最后一天;在 Quartz 中,星期字段中的 6L 表示最后一个星期五。
  • W 最近的工作日:15W 表示最接近 15 日的工作日。
  • # 当月第 N 个星期几:按 Quartz 和 AWS 的编号,6#3 表示第三个星期五。

L、W 和 # 是扩展语法,经典 Unix cron 不支持。

日与星期字段

当两个日期字段都受到限制时,不同系统对如何组合它们的看法不一。在经典 Unix cron 中,只要任一字段匹配,任务就会运行:0 9 13 * 5 会在每月 13 日以及每个星期五运行,而不只是在 13 日恰逢星期五时运行。Spring 要求两者同时匹配。Quartz 和 AWS 则要求两个字段之一必须为 ?,从而回避了这个问题。

LeedyBox Cron 解析器会应用您所选格式的规则,并在摘要中说明是满足其一即可,还是两者都必须匹配。

时区与夏令时

cron 表达式本身不包含时区。它按执行它的系统或服务的时区运行,可能是服务器的本地时间,也可能是 UTC。按本地时间 09:00 编写的任务,如果服务器使用 UTC,可能会在另一个钟点运行。

夏令时还会带来更多边界情况。时钟拨快时,02:30 这样的时间在当天可能不存在;时钟拨回时,它可能出现两次。根据实现的不同,处于该时段的任务可能被跳过、延迟运行或运行两次。将重要任务安排在切换时段之外,或使用 UTC,可以减少意外。Cron 解析器允许您选择时区并列出下次运行时间,方便您检查切换前后的日期。

常见问题

如何每 5 分钟运行一次任务?

在 Unix cron 中使用 */5 * * * *。在 Spring 中,需要在开头加上秒字段:0 */5 * * * *。

为什么我的 Quartz 表达式在 Linux crontab 中无法使用?

Quartz 表达式以秒字段开头,并且可能使用 ? 或 L,而 crontab 不接受这些写法。请将表达式改写为 5 个字段的格式。

解析器显示的下次运行时间准确吗?

它们是在您的浏览器中按所选格式和时区计算的。由于各实现可能有所不同,请在实际运行任务的系统上确认计划。