你常常需要处理一些计划任务——从每日数据备份、日志清理,到定时推送通知、周期性数据同步等等。CRON 表达式提供了一种简单而强大的方式精准控制这些任务的执行时间,
本文将解析 CRON 表达式的结构、语法、特殊字符用法,并对比 Unix/Linux 与 Java Quartz 的差异,助你写出准确可靠的调度规则。
一、什么是 CRON 表达式?
CRON 表达式是一种由空格分隔的字段组成的字符串,用于描述任务应何时执行。它起源于 Unix 系统的 cron 守护进程,如今已被广泛应用于各类调度框架(如 Linux crontab、Spring Boot 的 @Scheduled、Quartz、Airflow 等)。
虽然核心思想一致,但不同系统对 CRON 表达式的实现略有差异。最常见的有两种:
- Unix/Linux 原生 cron:5 个字段(分钟、小时、日、月、周)
- Quartz(Java 调度库):6 或 7 个字段(增加“秒”,可选“年”)
本文以 Quartz 标准(6 字段) 为主讲解,因其功能更丰富,且被 Spring 等主流框架采用。
二、CRON 表达式的基本结构
一个标准的 Quartz CRON 表达式包含以下 6 个必填字段(第 7 个“年”为可选):
ounter(line秒 分 时 日 月 周 [年]字段 | 含义 | 允许值 |
1. 秒(Seconds) | 0–59 | 0, */10, 5,15,25 |
2. 分(Minutes) | 0–59 | 0, 30, */15 |
3. 小时(Hours) | 0–23(0=午夜) | 8, 9-17 |
4. 日(Day of month) | 1–31 | 1, L, 15W |
5. 月(Month) | 1–12 或 JAN–DEC | 1, JUN, */3 |
6. 周(Day of week) | 0–7(0/7=周日)或 SUN–SAT | MON, 6#2, ? |
7. 年(Year)【可选】 | 1970–2099 | 2025, 2025-2030 |
注意:Unix cron 没有“秒”和“年”字段,只有后 5 项。
三、特殊字符:构建灵活调度的关键
CRON 的强大之处在于其支持多种特殊字符,让你能表达复杂的周期逻辑:
字符 | 含义 | 使用场景 | 示例 |
* | 任意值 | 所有可能值 | * in Minutes → 每分钟 |
? | 不指定 | 仅用于“日”或“周”之一 | 避免冲突(见下文) |
- | 范围 | 连续区间 | 9-17 → 9点到17点 |
, | 列表 | 多个离散值 | MON,WED,FRI |
/ | 步长 | 间隔执行 | */5 in Seconds → 每5秒 |
L | Last(最后) | 日或周字段 | L → 该月最后一天;6L → 最后一个星期五 |
W | 最近的工作日 | 仅用于“日” | 15W → 最接近15号的周一至周五 |
# | 第 N 个某天 | 仅用于“周” | 6#3 → 该月第3个星期五 |
⚠️ 关键规则:?的使用
“日”(Day of month)和“周”(Day of week)是互斥的——你不能同时指定具体日期和具体星期几。此时必须用 ? 表示“不关心”。
✅ 正确:
- 固定日期:0 0 12 15 * ? → 每月15日中午12点
- 固定星期:0 0 12 ? * FRI → 每周五中午12点
❌ 错误:
- 0 0 12 15 * FRI → 同时指定了15号和周五,会报错!
四、常见场景与表达式示例
需求 | Quartz 表达式 | 说明 |
每分钟执行一次 | 0 * * * * ? | 秒=0,每整分钟 |
每5分钟 | 0 */5 * * * ? | |
每天凌晨2点 | 0 0 2 * * ? | |
工作日上午9点 | 0 0 9 ? * MON-FRI | |
每月1号0点 | 0 0 0 1 * ? | |
每月最后一天中午 | 0 0 12 L * ? | |
每月第一个周一 | 0 0 9 ? * MON#1 | |
每10秒执行(仅 Quartz) | */10 * * * * ? | Unix 不支持 |
每年元旦0点(带年) | 0 0 0 1 1 ? 2025 | 7字段格式 |
五、Unix cron vs Quartz:关键区别
特性 | Unix/Linux cron | Quartz (Java) |
字段数量 | 5 | 6(+1可选年) |
支持“秒” | ❌ | ✅ |
支持 L, W, #, ? | ❌ | ✅ |
最小时间粒度 | 分钟 | 秒 |
年字段 | 不支持 | 支持(第7位) |
常见用途 | 系统级任务(如日志轮转) | 应用级调度(如 Spring Boot) |
提示:在 Spring Boot 中使用 @Scheduled(cron = "...") 时,默认采用 Quartz 风格(6字段),但不支持“秒”字段!Spring 的 cron 是 5字段(分 时 日 月 周),与 Unix 一致。这是开发者常踩的坑!
六、实用建议与避坑指南
- 明确你的调度框架先确认使用的是 Unix cron、Quartz 还是 Spring cron,避免表达式不兼容。
- 慎用月末日期如 31 在 2 月或 4 月会被忽略,可能导致任务未执行。
- 测试你的表达式使用在线工具验证:
- crontab.guru(Unix 风格)
- FreeFormatter Cron Generator(Quartz 风格)
- 注意时区问题cron 默认使用服务器本地时区。在分布式系统中,建议统一使用 UTC 或配置时区。
- 避免过度复杂如果逻辑太复杂(如“每月最后一个工作日”),考虑在代码中判断,而非强行用 CRON 表达式。
七、结语
掌握 CRON 表达式的关键在于理解 每个字段的含义 和 特殊字符的组合逻辑。建议多练习、多测试,尤其注意不同调度框架的差异。
