Linux 定时任务最常用的就是 cron,但写表达式时总会碰到几个经典问题:第 5 段到底是"星期几"还是"星期几(1-7,周日为 1)"?0 0 * * 0 和 0 0 * * 7 有区别吗?Quartz 的 cron 比 Linux 多两段,第 6 段到底是"年"还是"秒"?

这篇文章把 cron 表达式的 6 段语法讲透,配合在线解析工具把抽象的表达式变成可读的"什么时候执行"说明,解决"看懂已有表达式"和"写出正确表达式"两个高频痛点。

基本语法(Linux cron 5 段)

* * * * * command
│ │ │ │ │
│ │ │ │ └── 星期几(0-7,0 和 7 都是周日)
│ │ │ └──── 月份(1-12)
│ │ └────── 日期(1-31)
│ └──────── 小时(0-23)
└────────── 分钟(0-59)

Quartz 扩展为 6 段,前面多一个 秒(注意 Spring 的 @Scheduled 虽然也是 6 段,但周字段仍按 0-7、0 和 7 为周日,与本图不同):

* * * * * *
│ │ │ │ │ │
│ │ │ │ │ └── 星期几(1-7,周日为 1)
│ │ │ │ └──── 月份(1-12)
│ │ │ └────── 日期(1-31)
│ │ └──────── 小时(0-23)
│ └────────── 分钟(0-59)
└──────────── 秒(0-59)

核心陷阱:0 0 * * 0 vs 0 0 * * 7

Linux cron 中,星期几字段 0 和 7 都是周日——最初 cron 只认 0,后续实现为兼容旧写法又接受了 7,所以 0-7 都合法,两个表达式在 Linux 上行为一致。

# 这两条在 Linux 上等价:每周日零点执行
0 0 * * 0  cleanup.sh
0 0 * * 7  cleanup.sh

关键坑:Spring 的 @Scheduled 也是 6 段(秒在前),但周字段规则和 Linux 完全一致——取值 0-7,0 和 7 都是周日,1 是周一,所以 Linux 的 0 0 * * 1 在 Spring 里写成 0 0 0 * * 1,仍是每周一。真正相反的是 Quartz:周字段是 1-7,1 表示周日、7 表示周六,而且「日」和「周」两个字段必须有一个写成 ?。所以同一组数字搬到 Quartz 写成 0 0 0 ? * 1,含义就变成每周日——看着只多了一个秒字段,执行时间却差了一天。

每段支持的特殊字符

字符 含义 示例 说明
* 任意值 * * * * * 每分钟执行
, 枚举 1,3,5 * * * * 每小时的第 1/3/5 分钟执行
- 范围 0-30 * * * * 每小时前 30 分钟每分钟
/ 步长 */5 * * * * 每 5 分钟(0,5,10,15...)
? 忽略(仅 Quartz) 0 0 0 * * ? 「日」和「周」必须有且只有一个写成 ?
L 最后(仅日期/星期) 0 0 0 L * ? 每月最后一天零点
W 工作日(仅日期) 0 0 0 15W * ? 离每月 15 号最近的工作日

最容易写错的:*/5 不是"每 5 分钟",而是"从 0 开始,每隔 5 分钟"——*/5 * * * * 和 0-59/5 * * * * 等价,都是 0,5,10...55。但 3/5 * * * * 是 3,8,13...58。

用在线解析工具验证

光靠脑子想很容易搞错,把表达式粘进 Cron 表达式在线解析 工具:

  • 手动切换 Linux 5 段 / Spring 6 段 / Quartz 6-7 段,选对模式才不会把段数和周字段读错
  • 常用示例按钮跟着模式变:Linux 用 5 段、Spring 补秒字段、Quartz 再用 ? 占位并把周字段按 1 = 周日 重算,点一下就是该模式下的正确写法
  • 解析后显示"执行计划预览"——未来 5 次执行时间,一眼看出 0 0 * * 0 是不是周日
  • 对可疑的表达式(比如日期和星期同时指定、用了 7 作周日、Quartz 里写 0 当周日)给出黄色警告
  • 切换模式后警告会跟着变,同一条表达式在三种框架下的合法性一次看清

常见坑

  • "日期 + 星期"同时指定:0 0 1 * 1 在 Linux 上是"每月 1 号 或 周一"(OR 关系),很多人以为是 AND。Quartz 里必须用 ? 放弃其中一个。
  • 月份字段从 1 开始还是 0:月份永远是 1-12,不要和 Java 的 Calendar.MONTH(0-11)搞混。
  • */1 和 * 不一样吗:执行结果完全一样,但 */1 可读性差,建议直接写 *。
  • 秒级调度:Linux cron 最小粒度是分钟,需要秒级请用 Quartz。

相关工具与速查