异常现象

使用quartz定时器解析部分cron表达式时,抛出ParseException异常:Support for specifying both a day-of-week AND a day-of-month parameter is not implemented

异常原因

该异常原因为:Quartz 对 “Day of Month” 和 “Day of Week” 字段的互斥原则,“日”(Day of Month)和“周几”(Day of Week)这两个字段不能同时使用 * 或具体值。即:

  • 如果指定了 * 在“日”字段,那么“周几”字段应使用 ?
  • 反之亦然:如果在“周几”用了 MON-FRI,那么“日”字段应该用 ? 来表示“不指定”

否则,Quartz 会认为存在 调度歧义(到底是按日还是按周?),从而抛出异常。

代码测试验证

import org.quartz.CronExpression;

public class CronTest {
    public static void main(String[] args) {
        String cron1 = "0 0 15 * * MON-FRI"; // ❌ 会失败
        String cron2 = "0 0 15 ? * MON-FRI"; // ✅ 正确
        try {
            CronExpression.validateExpression(cron1);
            System.out.println("cron1 is valid");
        } catch (Exception e) {
            System.out.println("cron1 invalid: " + e.getMessage());// ❌ 异常输出
        }
        try {
            CronExpression.validateExpression(cron2);
            System.out.println("cron2 is valid"); // ✅ 正常输出
        } catch (Exception e) {
            System.out.println("cron2 invalid: " + e.getMessage());
        }
    }
}

Quartz 中的最佳实践

//推荐写法:使用 ? 表示“日”字段不参与调度
0 13,53 15 ? * MON-FRI
//或者更明确地加上年(可选)
0 13,53 15 ? * MON-FRI *

Quartz Cron 表达式格式说明

Quartz 使用的是 7 个字段 的 Cron 表达式格式(与标准 Unix cron 不同):

字段 允许值 是否必需 示例
秒(Seconds) 0-59 0
分钟(Minutes) 0-59 0
小时(Hours) 0-23 15
日(Day of Month) 1-31 *
月(Month) 1-12 *
周几(Day of Week) 1-7 或 SUN-SAT MON-FRI
年(Year) 1970-2099(可选) * 或省略

⚠️ 注意:Quartz 支持 6 位或 7 位格式。如果省略第 7 位(年),默认为 *。

常见 Quartz Cron 示例

1. 每分钟执行一次

0 0/1 * * * ?

解释:每分钟的第 0 秒触发


2. 每5分钟执行一次

0 */5 * * * ?

或等价写法:

0 0,5,10,15,20,25,30,35,40,45,50,55 * * * ?

3. 每小时整点执行

0 0 * * * ?

每小时第 0 分钟、第 0 秒执行


4. 每天凌晨2点执行

0 0 2 * * ?

✅ 推荐:使用 ? 在“日”或“周几”字段之一


5. 每天中午12点执行

0 0 12 * * ?

6. 每月1号凌晨1点执行

0 0 1 1 * ?

7. 每月最后一天执行(不精确)

0 0 0 L * ?

L = Last day of month
⚠️ 注意:L 不支持所有场景,建议结合代码判断更准确


8. 每月最后一个周五

0 0 0 ? * 6L

6L = 本月最后一个星期五(6=Fri)


9. 每月第三个周一

0 0 0 ? * 2#3

2#3 = 第三个周一(2=Mon,#3=第3个)


10. 工作日(周一至周五)上午9点执行

0 0 9 ? * MON-FRI

✅ 推荐写法:使用 ? 表示“日”字段不参与调度


11. 周六和周日上午10点执行

0 0 10 ? * SAT,SUN

或写成:

0 0 10 ? * 7,1

12. 每季度第一天凌晨0点(如 1月1日、4月1日等)

0 0 0 1 1,4,7,10 ?

手动列出每个季度的第一个月


13. 每年1月1日零点执行

0 0 0 1 1 ?

14. 每个工作日的上午8点到下午6点,每两小时执行一次

0 0 8-18/2 ? * MON-FRI

8-18/2 = 从8点到18点,每隔2小时一次 → 8,10,12,14,16,18 点


15. 每30秒执行一次

0/30 * * * * ?

0/30 = 从第0秒开始,每30秒一次(即 :00 和 :30)


16. 上午9:15执行一次

0 15 9 * * ?

17. 每周二晚上8点执行

0 0 20 ? * TUE

或:

0 0 20 ? * 3

18. 每月第一个周六

0 0 0 ? * SAT#1

SAT#1 = 第一个周六


19. 每两月执行一次(如奇数月1号)

0 0 0 1 1/2 ?

1/2 = 从1月开始,每隔2个月 → 1,3,5,7,9,11月


20. 特定日期范围 + 时间(如国庆期间每天9点)

0 0 9 1-7 10 ?

10月1日至7日,每天9:00 执行

Cron格式校验工具推荐

https://www.freeformatter.com/cron-expression-generator-quartz.html

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐