
本文详解 quartz 中符合标准的 cron 表达式写法,重点验证“每月最后一天 23:15 触发”和“每 10 分钟触发”两种场景,并提供可立即验证的测试方案,避免依赖真实时间等待。
在 Quartz 调度框架中,cron 表达式虽借鉴 Unix cron,但采用 7 字段格式(秒 分 时 日 月 周 年),且支持特殊字符 L(Last)、W(Weekday)、#(第 N 个星期几)等扩展语法——这正是与 Linux cron 的关键区别。
✅ 每 10 分钟触发(正确):
"0 0/10 * * * ?"
- 说明:0(秒=0),0/10(分=从 0 开始,每 10 分执行一次 → 0,10,20,30,40,50),*(时=任意),*(日=任意),*(月=任意),?(周=不指定,因日已指定)。
- ❌ 原表达式 "0 10 * ? * *" 实际含义是:每天的 第 10 分钟(即 xx:10:00)触发一次,并非“每 10 分钟”。这是常见误解。
✅ 每月最后一天 23:15 触发(正确):
"0 15 23 L * ?"
- 说明:0(秒=0),15(分=15),23(时=23),L(日=当月最后一天),*(月=任意),?(周=不指定,避免冲突)。
- ✅ L 在日字段中明确表示“该月最后一天”,且与 ? 配合使用是 Quartz 推荐写法,完全可靠。
? 快速验证技巧(无需等到月底):
直接通过 Quartz 的 CronExpression 类进行逻辑校验,无需部署 Job 或等待真实时间:
import org.quartz.CronExpression;
public class CronTest {
public static void main(String[] args) {
String monthlyLast = "0 15 23 L * ?";
String every10min = "0 0/10 * * * ?";
CronExpression expr1 = new CronExpression(monthlyLast);
CronExpression expr2 = new CronExpression(every10min);
// 获取未来 5 次触发时间(毫秒级)
Date now = new Date();
for (int i = 0; i < 5; i++) {
Date next = expr1.getNextValidTimeAfter(now);
System.out.println("Next fire: " + next);
now = next;
}
}
}⚠️ 注意事项:
- Quartz cron 不支持 * 和 L 同时出现在日、周字段;务必用 ? 占位未使用的字段(日/周二选一);
- L 只在日字段中表示“月末最后一天”,在周字段中(如 6L)表示“当月最后一个周六”,语义不同;
- 生产环境建议结合 JUnit + Clock 注入或 TimeProvider 模拟系统时间,实现精准单元测试。
掌握标准语法 + 本地即时验证,即可高效、零风险地设计可靠调度逻辑。










