You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quartz Job触发时间重调度:节假日前后调整需求求助

Quartz Scheduler 节假日调度调整解决方案(支持前/后日偏移)

核心方案:自定义Calendar实现日期偏移逻辑

Quartz自带的Calendar仅支持排除日期,无法直接实现节假日的前/后日偏移,因此需要自定义Calendar来处理这个需求。

1. 定义节假日判断工具

首先实现一个工具类,用于判断指定日期是否为节假日:

public class HolidayUtils {
    // 模拟节假日数据源,实际可从数据库/配置文件加载
    private static final Set<String> HOLIDAYS = new HashSet<>(Arrays.asList(
        "2024-05-01", "2024-10-01", "2024-10-02"
    ));

    public static boolean isHoliday(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return HOLIDAYS.contains(sdf.format(date));
    }
}

2. 自定义AdjustableHolidayCalendar

继承Quartz的BaseCalendar,重写getNextIncludedTime方法,根据配置的偏移策略(前移/后移)调整触发时间:

public class AdjustableHolidayCalendar extends BaseCalendar {
    // 偏移策略:BEFORE=前一日,AFTER=后一日
    public enum AdjustStrategy {BEFORE, AFTER}

    private AdjustStrategy strategy;

    public AdjustableHolidayCalendar(AdjustStrategy strategy) {
        this.strategy = strategy;
    }

    @Override
    public long getNextIncludedTime(long time) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(time);
        
        // 判断当前时间是否为节假日,循环调整至非节假日
        while (HolidayUtils.isHoliday(cal.getTime())) {
            if (strategy == AdjustStrategy.BEFORE) {
                cal.add(Calendar.DATE, -1);
            } else {
                cal.add(Calendar.DATE, 1);
            }
            // 避免死循环,添加最大偏移限制(7天)
            if (Math.abs(cal.getTimeInMillis() - time) > 7 * 24 * 60 * 60 * 1000) {
                throw new RuntimeException("无法找到非节假日日期,超出最大偏移范围");
            }
        }
        return cal.getTimeInMillis();
    }
}

3. 绑定Calendar到Trigger

在创建月度/半年度/年度Trigger时,将自定义Calendar绑定到Trigger上,同时指定偏移策略:

// 初始化调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

// 配置「节假日前移」策略的Calendar
AdjustableHolidayCalendar beforeCalendar = new AdjustableHolidayCalendar(AdjustableHolidayCalendar.AdjustStrategy.BEFORE);
scheduler.addCalendar("beforeHolidayCalendar", beforeCalendar, false, false);

// 创建月度Trigger(每月1号触发)
CronTrigger monthlyTrigger = TriggerBuilder.newTrigger()
    .withIdentity("monthlyTrigger", "group1")
    .withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 1 * ?"))
    .modifiedByCalendar("beforeHolidayCalendar")
    .build();

// 配置「节假日后移」策略的Calendar
AdjustableHolidayCalendar afterCalendar = new AdjustableHolidayCalendar(AdjustableHolidayCalendar.AdjustStrategy.AFTER);
scheduler.addCalendar("afterHolidayCalendar", afterCalendar, false, false);

// 创建年度Trigger(每年1月1号触发)
CronTrigger annualTrigger = TriggerBuilder.newTrigger()
    .withIdentity("annualTrigger", "group1")
    .withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 1 1 ?"))
    .modifiedByCalendar("afterHolidayCalendar")
    .build();

// 注册Job并调度
JobDetail job = JobBuilder.newJob(YourBusinessJob.class)
    .withIdentity("businessJob", "group1")
    .build();

scheduler.scheduleJob(job, monthlyTrigger);
scheduler.scheduleJob(job, annualTrigger);
scheduler.start();

4. 补充说明

  • 节假日数据源可扩展为从数据库动态加载,支持实时新增/删除节假日
  • 可在自定义Calendar中添加周末是否视为节假日的判断逻辑
  • 最大偏移限制可根据业务需求调整,避免无限循环

内容的提问来源于stack exchange,提问作者Deepak Samria

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 07:17:24