Cron 表达式与 Crontab 表达式详解

引言

在开发定时任务时,我们经常接触到 Cron 表达式。然而,不同框架或系统中使用的 Cron 表达式格式并不统一——有 5 位、6 位甚至 7 位的写法,容易造成混淆。

更严重的是,如果表达式书写错误,可能导致:

  • 定时任务从未执行
  • 定时任务执行过于频繁

实际上,这里所说的 “Cron 表达式” 是一个广义概念,主要包括两类:

  1. 狭义的 Cron 表达式(常用于 Java 框架如 Quartz、Spring)
  2. Crontab 表达式(Unix/Linux 系统原生命令)

本文将系统梳理两者的语法、字段含义、特殊字符及使用示例。


一、Cron 表达式(6 位或 7 位)

1. 基本格式

Cron 表达式是一个字符串,由 5 或 6 个空格 分隔成 6 或 7 个域,每个域代表一个时间单位。

支持两种语法格式:

格式 字段顺序
6 位(常用) Seconds Minutes Hours DayOfMonth Month DayOfWeek
7 位(含年份) Seconds Minutes Hours DayOfMonth Month DayOfWeek Year

⚠️ 注意:“秒” 是 Java 生态(如 Spring、Quartz)特有的扩展,标准 Unix crontab 不包含秒

2. 各字段允许的取值与特殊字符

字段 允许值 特殊字符 说明
秒 (Seconds) 0–59 - * /
分 (Minutes) 0–59 - * / ,
小时 (Hours) 0–23 - * / ,
日期 (Day of Month) 1–31 - * ? / L W C 与星期互斥
月份 (Month) 1–12JAN–DEC - * / ,
星期 (Day of Week) 1–7SUN–SAT (1=周日, 2=周一, …, 7=周六) - * ? / L C # 与日期互斥
年 (Year) [可选] 1970–2099 , - * / 通常省略

3. 特殊字符含义

字符 含义 示例
* 匹配该域任意值 * 在分钟域 → 每分钟
? 仅用于日期或星期,表示“不指定”,用于解决两者互斥问题 0 0 0 20 * ?:每月 20 号触发,不管星期几
- 范围 5-20 在分钟域 → 5 到 20 分每分钟
/ 步长(从起始值开始,每隔 N 单位) 5/20 → 第 5 分,之后每 20 分(5, 25, 45…)
, 枚举多个值 5,20 → 5 分和 20 分
L “Last”,最后一天或最后一个星期几 (仅用于日期或星期) L 在日期 → 月末最后一天 5L 在星期 → 最后一个星期四
W “Workday”,最近的有效工作日(周一至周五) (仅用于日期) 15W → 若 15 号是周六,则在 14 号(周五)执行;若为周日,则在 16 号(周一)执行
LW 组合使用 → 某月最后一个工作日(即最后一个星期五) LW → 最后一个周五
# “第几个星期几” (仅用于星期) 4#2 → 某月第二个星期三(4=周三,2=第二个)
C “Calendar”,仅当日历中该日期存在时才触发 (仅用于日期) 较少使用

💡 关键规则
日期(DayOfMonth)和星期(DayOfWeek)不能同时指定具体值,必须有一个用 ?


4. 常见示例

表达式 含义
*/5 * * * * ? 每 5 秒执行一次
0 */1 * * * ? 每 1 分钟执行一次
0 0 2 1 * ? 每月 1 日凌晨 2 点执行
0 15 10 ? * MON-FRI 周一至周五上午 10:15 执行
0 0 23 * * ? 每天 23:00 执行
0 0 1 * * ? 每天凌晨 1 点执行
0 0 1 1 * ? 每年 1 月 1 日凌晨 1 点执行
0 0 23 L * ? 每月最后一天 23:00 执行
0 0 1 ? * L 每周日(星期天)凌晨 1 点执行
0 26,29,33 * * * ? 在 26、29、33 分各执行一次
0 0 10,14,16 * * ? 每天 10、14、16 点执行
0 0/30 9-17 * * ? 工作日 9–17 点间每 30 分钟执行
0 0 12 ? * WED 每周三中午 12 点执行
0 15 10 ? * 6L 每月最后一个星期五 10:15 执行
0 15 10 ? * 6#3 每月第三个星期五 10:15 执行
0 15 10 ? * * 2005 2005 年每天 10:15 执行

✅ 提示:在 Spring Boot 中,若未显式指定年份,表达式通常为 6 位;Quartz 支持 7 位。


二、Crontab 表达式(5 位)

1. 基本介绍

crontab 是 Unix/Linux 系统中用于设置周期性任务的命令。其守护进程 crond 每分钟检查一次是否有任务需要执行。

2. 格式

1
2
# 分 时 日 月 周   命令
m h dom mon dow command
字段 含义 取值范围
m 分钟 0–59
h 小时 0–23
dom 日期(日) 1–31
mon 月份 1–12JAN–DEC
dow 星期 0–7(0 和 7 都表示星期日)或 SUN–SAT

⚠️ 注意

  • 没有“秒”字段
  • 日期(dom)和星期(dow)可以同时指定,此时满足任一条件即触发(逻辑 OR)

3. 常见示例

表达式 含义
30 16 * * * /path/restart.sh 每天 16:30 执行
40 3 3,15,23 * * /path/restart.sh 每月 3、15、23 日 3:40 执行
30 3 * * 6,0 /path/restart.sh 每周六、周日 3:30 执行
0,30 20-22 * * * /path/restart.sh 每天 20:00–22:00 之间每 30 分钟执行
0 23 * * 6 /path/restart.sh 每周六 23:00 执行
0 */2 * * * /path/restart.sh 每 2 小时执行一次(0,2,4,…)
0 11 5 * mon-wed /path/restart.sh 每月 5 号 是周一到周三时,在 11:00 执行
0 5 1 jan * /path/restart.sh 每年 1 月 1 日 5:00 执行

💡 注意:mon-wed 是 crontab 支持的缩写,等价于 1-3


三、Cron vs Crontab 关键区别总结

特性 Cron 表达式(Java) Crontab(Linux)
字段数 6 或 7 位(含秒) 5 位(无秒)
秒字段 ✅ 支持 ❌ 不支持
日期 & 星期关系 互斥(必须一个为 ? 可同时指定(OR 关系)
星期起始 1 = 周日 0/7 = 周日
典型使用场景 Spring、Quartz、XXL-JOB Linux 系统定时任务

四、最佳实践建议

  1. 明确使用环境
    • Web 应用 → 用 6 位 Cron 表达式(含秒)
    • 服务器脚本 → 用 5 位 Crontab
  2. 避免歧义写法
    • 不要混用 * 和具体值在日期/星期上
    • 使用 ? 明确表示“不关心”
  3. 测试表达式
  4. 注释说明
    • 在代码或 crontab 文件中添加注释,说明触发逻辑

📌 记住
“能跑 ≠ 正确” —— 务必确认定时任务的触发频率是否符合业务预期!