Cron 表达式:定时任务规则速查
"每天凌晨 3 点备份数据库"、"每周一 9 点发周报"、"每月 1 号清理日志"——定时任务无处不在。Cron 表达式是行业标准,但语法晦涩难记。本文详解 Cron 规则、常用示例、各平台差异。
什么是 Cron?
Cron 来源于 Unix/Linux 系统的定时任务调度器 cron。Cron 表达式是一串字符,定义任务执行的时间和频率。
标准 5 段格式
* * * * *
│ │ │ │ │
│ │ │ │ └── 周几 (0-7, 0 和 7 都是周日)
│ │ │ └──── 月份 (1-12)
│ │ └────── 日期 (1-31)
│ └──────── 小时 (0-23)
└────────── 分钟 (0-59)
扩展 6 段格式
* * * * * *
│ │ │ │ │ │
│ │ │ │ │ └── 周几 (0-7)
│ │ │ │ └──── 月份 (1-12)
│ │ │ └────── 日期 (1-31)
│ └──────── 小时 (0-23)
└────────── 分钟 (0-59)
最前面增加"秒"字段(0-59)。Spring、Quartz 用 6 段或 7 段格式。
7 段格式
* * * * * * *
│ │ │ │ │ │ │
│ │ │ │ │ │ └── 年份 (可选)
│ │ │ │ │ └──── 周几
│ │ │ │ └────── 月份
│ │ │ └──────── 日期
│ └─────────── 小时
└───────────── 分钟
↑ 秒
Quartz 用 7 段格式。
字段值范围
| 字段 | 允许值 | 特殊字符 |
| 秒(6/7 段) | 0-59 | , - * / |
| 分钟 | 0-59 | , - * / |
| 小时 | 0-23 | , - * / |
| 日期 | 1-31 | , - * / ? L W C |
| 月份 | 1-12 或 JAN-DEC | , - * / |
| 周几 | 0-7 或 SUN-SAT (0 和 7 都是周日) | , - * / ? L # C |
| 年份 | 1970-2099 或空 | , - * / |
特殊字符含义
* 任意值
* * * * * → 每分钟
, 列举
0 0,12 * * * → 每天 0 点和 12 点
- 范围
0 9-17 * * * → 每天 9 点到 17 点整点
/ 步长
*/5 * * * * → 每 5 分钟
0 */2 * * * → 每 2 小时整点
0 0 1 */3 * → 每 3 个月的 1 号 0 点
? 不指定(仅日期和周几)
日期和周几字段不能同时用 *,必须有一个用 ?:
0 0 * * ? → 每天 0 点(周几不指定)
0 0 ? * MON → 每周一 0 点(日期不指定)
L 最后(Last)
0 0 L * * → 每月最后一天 0 点
0 0 * * 5L → 每月最后一个周五
W 最近工作日
0 0 15W * * → 每月 15 号最近的工作日 0 点
如果 15 号是周六,触发 14 号;如果是周日,触发 16 号。
# 第 N 个工作日
0 0 ? * 2#3 → 每月第三个周一 0 点
格式:周几#第N个。
C 日历(Quartz 特有)
很少用。
常用 Cron 表达式速查
高频任务
| 表达式 | 含义 |
* * * * * | 每分钟 |
*/5 * * * * | 每 5 分钟 |
*/30 * * * * | 每 30 分钟 |
0 * * * * | 每小时整点 |
0 */2 * * * | 每 2 小时整点 |
0 0 * * * | 每天 0 点 |
0 12 * * * | 每天 12 点 |
每日任务
| 表达式 | 含义 |
0 0 * * * | 每天午夜 |
0 1 * * * | 每天凌晨 1 点 |
0 6 * * * | 每天早上 6 点 |
0 9 * * * | 每天上午 9 点 |
0 18 * * * | 每天下午 6 点 |
0 22 * * * | 每天晚上 10 点 |
0 23 * * * | 每天晚上 11 点 |
30 8 * * * | 每天 8:30 |
45 9 * * * | 每天 9:45 |
每周任务
| 表达式 | 含义 |
0 0 * * 0 | 每周日 0 点 |
0 0 * * 1 | 每周一 0 点 |
0 9 * * 1 | 每周一 9 点 |
0 0 * * 6 | 每周六 0 点 |
0 0 * * 1-5 | 工作日 0 点 |
0 9 * * 1-5 | 工作日 9 点 |
0 18 * * 5 | 每周五 18 点 |
每月任务
| 表达式 | 含义 |
0 0 1 * * | 每月 1 号 0 点 |
0 0 15 * * | 每月 15 号 0 点 |
0 0 L * * | 每月最后一天 0 点 |
0 0 3 * * | 每月 3 号 0 点 |
每年任务
| 表达式 | 含义 |
0 0 1 1 * | 每年 1 月 1 日 0 点 |
0 0 1 10 * | 每年 10 月 1 日 0 点 |
实际业务示例
| 场景 | 表达式 |
| 数据库备份 | 0 3 * * *(每天 3 点) |
| 清理临时文件 | 0 4 * * *(每天 4 点) |
| 发送日报 | 0 9 * * 1-5(工作日 9 点) |
| 发送周报 | 0 18 * * 5(每周五 18 点) |
| 发送月报 | 0 9 1 * *(每月 1 号 9 点) |
| 检查 SSL 证书 | 0 0 1 * *(每月 1 号 0 点) |
| 同步用户数据 | */10 * * * *(每 10 分钟) |
| 心跳检查 | */1 * * * *(每分钟) |
| 月底统计 | 0 0 L * *(每月最后一天 0 点) |
| 季度报告 | 0 0 1 1,4,7,10 *(每季度首月 1 号 0 点) |
52tool Cron 工具
工具地址:Cron 表达式生成器
功能
- 可视化生成(点选字段)
- 实时显示下次执行时间
- 校验表达式合法性
- 反向解析(看表达式含义)
- 浏览器端运行
实战 1:生成每周一 9 点
可视化点选:
- 分钟:0
- 小时:9
- 日期:*
- 月份:*
- 周几:周一(1)
输出:
0 9 * * 1
下次执行:2026-08-03 09:00:00(下周一)
实战 2:校验表达式
输入:
0 9 * * 1
输出:
合法:每周一 9:00
下次执行:2026-08-03 09:00:00
实战 3:反向解析
输入陌生表达式:
0 0 1W * *
输出:
每月 1 号最近的工作日 0:00
下次执行:2026-09-01 00:00:00
不同平台差异
Linux Cron
5 段格式,无秒。
0 3 * * * /usr/bin/backup.sh
最小粒度:1 分钟。不支持秒。
Spring @Scheduled
支持 6 段格式(含秒):
@Scheduled(cron = "0 0 9 * * MON")
public void weeklyReport() {
// 每周一 9 点
}
Quartz Scheduler
7 段格式(含秒和年):
0 0 9 ? * MON *
注意日期和周几必须有一个是 ?。
K8s CronJob
5 段格式:
apiVersion: batch/v1
kind: CronJob
metadata:
name: backup
spec:
schedule: "0 3 * * *"
jobTemplate:
spec:
containers:
- name: backup
image: backup:v1
AWS EventBridge
6 段格式(含年):
0 9 ? * MON *
字段顺序与标准不同:分 时 日 月 周 年。
GitHub Actions
不支持 Cron 完整语法,用 cron: 字段:
on:
schedule:
- cron: '0 9 * * 1'
最小 5 分钟,且不保证准时。
常见错误
错误 1:日期和周几都用 *
0 0 * * * ← 错误
Linux 允许,但 Quartz 报错。建议明确:
0 0 * * ? ← 每天
0 0 ? * * ← 每天(另一种写法)
错误 2:忘记秒(Quartz)
0 9 * * MON ← 在 Quartz 中变成 0 秒 0 分 9 点
Quartz 需要 6 段或 7 段。
错误 3:周日是 0 还是 7
- Linux:0 和 7 都是周日
- Quartz:1-7(1 是周日)
- Spring:0 和 7 都是周日
跨平台时注意。
错误 4:月份缩写大小写
0 0 1 JAN * ← 大写
0 0 1 jan * ← 小写
0 0 1 Jan * ← 混合
多数实现大小写不敏感,但建议统一大写。
错误 5:误用 */0
*/0 * * * * ← 无效
步长必须大于 0。
时区问题
服务器时区不同
服务器 UTC,要北京时间 9:00 → 0 1 * * *(UTC 1 点)
UTC+8 比 UTC 早 8 小时,北京时间 9:00 = UTC 1:00。
Spring 解决方案
@Scheduled(cron = "0 0 9 * * *", zone = "Asia/Shanghai")
public void dailyTask() {
// 北京时间 9 点执行
}
Docker 容器
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
容器时区设为东八区,Cron 用北京时间。
实战技巧
技巧 1:错峰执行
避免所有任务都设 0 点:
0 0 * * * → 服务器负载高峰
30 2 * * * → 错峰 2:30
15 3 * * * → 3:15
0 */3 * * * → 每 3 小时
技巧 2:跨时区协调
多地数据中心备份任务错开:
北京:0 1 * * * (UTC 17:00 前一天)
美西:0 9 * * * (UTC 17:00 当天)
欧洲:0 23 * * * (UTC 23:00 当天)
技巧 3:用工具生成
复杂表达式手写易错,用 52tool Cron 生成器 可视化点选。
技巧 4:测试 Cron
# Linux 测试不实际执行
crontab -l
# 模拟下次执行时间
crontab -l | awk 'NF && !/^#/ {print "Next run: " $0}'
或在 52tool Cron 工具 输入表达式查看下次执行时间。
与其他工具配合
Cron + JSON
工具:JSON 格式化
定时任务的配置(JSON 格式)格式化查看。
Cron + YAML
工具:YAML/JSON 转换
K8s CronJob 配置是 YAML,转 JSON 看结构。
Cron + 时间戳
工具:时间戳转换
下次执行时间转 Unix 时间戳存数据库。
常见问题解答
Q: Cron 表达式怎么记?
A: 不用记。用 52tool Cron 生成器 可视化点选,常用表达式存备忘录。常用就那么 10 来个,多看几次就熟了。
Q: Cron 和 Quartz 表达式一样吗?
A: 不完全一样。Quartz 用 6 段或 7 段(含秒和可选年份),且日期和周几不能同时用 *。Linux Cron 用 5 段(无秒)。
Q: Cron 能精确到秒吗?
A: 标准 Cron 不能。Spring 和 Quartz 的扩展格式支持秒。需要更精细的调度用其他方案(如 Quartz Trigger)。
Q: Cron 任务执行慢,下次时间到了怎么办?
A: 默认行为是新任务不执行(错过的跳过)。某些实现可配置"错过补执行"。建议任务设计成幂等,多次执行无副作用。
Q: GitHub Actions Cron 准时吗?
A: 不保证。GitHub 可能延迟几分钟甚至几小时,且不支持秒。重要任务用专门调度器(如 Airflow)。
Q: 工具会泄露我的 Cron 表达式吗?
A: 52tool Cron 工具在浏览器端运行,表达式不上传服务器。Cron 通常含业务时间信息(如备份时间),用浏览器端工具更安全。
总结
Cron 表达式语法晦涩但功能强大:
- 可视化生成 → 52tool Cron 生成器
- 平台差异 → 注意段数、周日编号
- 时区问题 → 用 zone 参数或统一 UTC
记住:写 Cron 用工具生成,避免手写出错;生产环境加日志,确认任务按时执行。