Please see
http://forums.opensymphony.com/thread.jspa?threadID=50883&tstart=0
There appears to be a severe bug in CronExpression (or CronTrigger, depending what version of quartz is being used) that prevents correct handling of trigger calculation in some situations. In particular, the problem can be reproduced with the following code:
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yy");
CronTrigger fiveDayTrigger = new CronTrigger("fiveTrigger", "TEST", "0 0 12 1/5 * ? *");
fiveDayTrigger.setStartTime(dateFormat.parse("02/25/07"));
fiveDayTrigger.setEndTime(dateFormat.parse("03/31/07"));
Date now = new Date();
Date nextFireTime = fiveDayTrigger.getFireTimeAfter(dateFormat.parse("1/31/07"));
while (nextFireTime != null) {
System.out.println(dateFormat.format(nextFireTime));
nextFireTime = fiveDayTrigger.getFireTimeAfter(nextFireTime);
}
(Note that the above code does not add the trigger to the scheduler, which does not make it a complete test, but I have tried adding this step with no effect on the results)
Running this code, you'll note that 3/1/2007 is skipped. Tracing the code, it appears to me that the problem is somewhere in CronExpression.getTimeAfter(Date).
Again, please see the mentioned forum entry for more information.
.....
tcal.set(Calendar.HOUR_OF_DAY, hr);
tcal.set(Calendar.DAY_OF_MONTH, day);
tcal.set(Calendar.MONTH, mon - 1);
Date nTime = tcal.getTime();
if(nTime.before(afterTime)) {
day = ((Integer) daysOfMonth.first()).intValue();;
mon++;
}
} else if (st != null && st.size() != 0) {
t = day;
day = ((Integer) st.first()).intValue();
// ============ Patch ===========
// check if 'day' should be taken in next month
int lastDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));
if (day > lastDay) {
day = ((Integer) daysOfMonth.first()).intValue();;
mon++;
}
// ==============================
} else {
day = ((Integer) daysOfMonth.first()).intValue();
mon++;
}
if (day != t || mon != tmon) {
cl.set(Calendar.SECOND, 0);
cl.set(Calendar.MINUTE, 0);
cl.set(Calendar.HOUR_OF_DAY, 0);
...