我可以使用Quartz Scheduler在第30天每隔一个月开一次,但如果月没有第30天,那么最后一天会开火吗?

时间:2014-09-24 13:40:04

标签: java quartz-scheduler jboss-eap-6

我可以使用Quartz Scheduler库创建具有以下设置的计划吗?:

  • 2014年12月30日
  • 开始
  • 每隔30天执行
  • 每隔2个月因此
  • 如果月份没有第30天,则应在最后一天进行操作。

因此,产生的时间表将是:

  • 2014年12月30日
  • 2月 28 ,2015
  • 2015年4月30日
  • ......等等

从我所学到的:

  1. CronTrigger不允许这样做(可以设置为仅在特定月份触发,而不是间隔),
  2. CalendarIntervalTrigger将跳过没有第30天的月份(由以下代码创建的触发器)

    try {
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.start();
    
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("HelloJob_CalendarIntervaled", "calendarIntervaled")
                .build();
    
        Calendar decemberThirty = Calendar.getInstance();
        decemberThirty.set(Calendar.YEAR, 2014);
        decemberThirty.set(Calendar.MONTH, Calendar.DECEMBER);
        decemberThirty.set(Calendar.DAY_OF_MONTH, 30);
    
        CalendarIntervalTrigger calendarIntervalTrigger = newTrigger()
                .withIdentity("calendarIntervalTrigger", "calendarIntervaled")
                .withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
                        .withIntervalInMonths(2))
                .startAt(decemberThirty.getTime())
                .forJob(jobDetail)
                .build();
    
        scheduler.scheduleJob(jobDetail, calendarIntervalTrigger);
    
        System.out.println(calendarIntervalTrigger.getNextFireTime());
    } catch (SchedulerException e) {
        e.printStackTrace();
    }
    
  3. 如果不是,有没有其他选择(它应该适用于JBoss eap 6.2.0)?

1 个答案:

答案 0 :(得分:6)

你可以在Quartz中实现这一点,但是你必须通过使用CalendarIntervalTrigger来触发一个Job来计算你的'真正的'Job应该被安排的时间来扭转正常行为。

您计划一个触发器,该触发器每隔一个计划月份触发一次:

[...]
JobDetail jobDetail = newJob(SchedulingCalculationJob.class)
        .withIdentity("SchedulingCalculation_CalendarIntervaled", "calendarIntervaled")
        .build();

CalendarIntervalTrigger calendarIntervalTrigger = newTrigger()
        .withIdentity("calendarIntervalCalculationTrigger", "calendarIntervaled")
        .withSchedule(calendarIntervalSchedule()
                .withIntervalInMonths(2))
        .startAt(decemberFirst.getTime())
        .forJob(jobDetail)
        .build();

scheduler.scheduleJob(jobDetail, calendarIntervalTrigger);

SchedulingCalculationJob工作中,您计算​​了'真正的'工作安排日:

public class SchedulingCalculationJob implements Job {

    public void execute(JobExecutionContext context)
            throws JobExecutionException {

        Calendar calendar = calculateJobFiringDate();

        // Create and schedule a dedicated trigger
        Trigger calculateFiring = calculateFiring = newTrigger()
               .withSchedule(SimpleSchedulerBuilder.simpleScheduler())
               .startAt(calendar.getTime())
               .forJob(yourRealJobDetail)
               .build();

        scheduler.scheduleJob(yourRealJobDetail, calculateFiring);
    }

    public static Calendar calculateJobFiringDate() {
        Calendar result = Calendar.getInstance();

        // Set up the scheduling day
        if (isThereThirtyDaysInCurrentMonth()) {
            // the 30th of the current month
            calendar.set(Calendar.DAY_OF_MONTH, 30);
        } else {
            // the last day of the current month
            calendar.add(Calendar.MONTH, 1);
            calendar.add(Calendar.DATE, -1);
        }

        // Set up time of day
        calendar.set(Calendar.HOUR, ...);
        calendar.set(Calendar.MINUTE, ...);
        calendar.set(Calendar.SECOND, ...);

        return result;
    }

    public static boolean isThereThirtyDaysInCurrentMonth() {
        Calendar thirtydaysInCurrentMonthCalendar = Calendar.getInstance();

        Integer currentMonth = thirtydaysInCurrentMonthCalendar.get(Calendar.MONTH);
        thirtydaysInCurrentMonthCalendar.add(Calendar.DATE, 29);

        return (currentMonth == thirtydaysInCurrentMonthCalendar.get(Calendar.MONTH);
    }
}

这有点麻烦,但我已经使用它,我工作正常。