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
相关产品推荐
相关产品推荐

