The search for the next execution time can be limited by a date/time barrier so searches for february 30th will no longer result in an endless loop
This commit is contained in:
parent
3c2006d412
commit
b2e7da3170
|
@ -174,6 +174,20 @@ public class CronExpression {
|
|||
}
|
||||
|
||||
public DateTime nextTimeAfter(DateTime afterTime) {
|
||||
// will search for the next time within the next 4 years. If there is no
|
||||
// time matching, an InvalidArgumentException will be thrown (it is very
|
||||
// likely that the cron expression is invalid, like the February 30th).
|
||||
return nextTimeAfter(afterTime, afterTime.plusYears(4));
|
||||
}
|
||||
|
||||
public DateTime nextTimeAfter(DateTime afterTime, long durationInMillis) {
|
||||
// will search for the next time within the next durationInMillis
|
||||
// millisecond. Be aware that the duration is specified in millis,
|
||||
// but in fact the limit is checked on a day-to-day basis.
|
||||
return nextTimeAfter(afterTime, afterTime.plus(durationInMillis));
|
||||
}
|
||||
|
||||
public DateTime nextTimeAfter(DateTime afterTime, DateTime dateTimeBarrier) {
|
||||
MutableDateTime nextTime = new MutableDateTime(afterTime);
|
||||
nextTime.setMillisOfSecond(0);
|
||||
nextTime.secondOfDay().add(1);
|
||||
|
@ -207,6 +221,7 @@ public class CronExpression {
|
|||
}
|
||||
nextTime.addDays(1);
|
||||
nextTime.setTime(0, 0, 0, 0);
|
||||
checkIfDateTimeBarrierIsReached(nextTime, dateTimeBarrier);
|
||||
}
|
||||
if (monthField.matches(nextTime.getMonthOfYear())) {
|
||||
break;
|
||||
|
@ -214,17 +229,25 @@ public class CronExpression {
|
|||
nextTime.addMonths(1);
|
||||
nextTime.setDayOfMonth(1);
|
||||
nextTime.setTime(0, 0, 0, 0);
|
||||
checkIfDateTimeBarrierIsReached(nextTime, dateTimeBarrier);
|
||||
}
|
||||
if (dayOfWeekField.matches(new LocalDate(nextTime))) {
|
||||
break;
|
||||
}
|
||||
nextTime.addDays(1);
|
||||
nextTime.setTime(0, 0, 0, 0);
|
||||
checkIfDateTimeBarrierIsReached(nextTime, dateTimeBarrier);
|
||||
}
|
||||
|
||||
return nextTime.toDateTime();
|
||||
}
|
||||
|
||||
private static void checkIfDateTimeBarrierIsReached(MutableDateTime nextTime, DateTime dateTimeBarrier) {
|
||||
if (nextTime.isAfter(dateTimeBarrier)) {
|
||||
throw new IllegalArgumentException("No next execution time could be determined that is before the limit of " + dateTimeBarrier);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "<" + expr + ">";
|
||||
|
|
|
@ -442,4 +442,28 @@ public class CronExpressionTest {
|
|||
public void shall_not_not_support_rolling_period() throws Exception {
|
||||
new CronExpression("* * 5-1 * * *");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void non_existing_date_throws_exception() throws Exception {
|
||||
// Will check for the next 4 years - no 30th of February is found so a IAE is thrown.
|
||||
new CronExpression("* * * 30 2 *").nextTimeAfter(DateTime.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_default_barrier() throws Exception {
|
||||
// the default barrier is 4 years - so leap years are considered.
|
||||
assertThat(new CronExpression("* * * 29 2 *").nextTimeAfter(new DateTime(2012, 3, 1, 00, 00))).isEqualTo(new DateTime(2016, 2, 29, 00, 00));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void test_one_year_barrier() throws Exception {
|
||||
// The next leap year is 2016, so an IllegalArgumentException is expected.
|
||||
new CronExpression("* * * 29 2 *").nextTimeAfter(new DateTime(2012, 3, 1, 00, 00), new DateTime(2013, 3, 1, 00, 00));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void test_two_year_barrier() throws Exception {
|
||||
// The next leap year is 2016, so an IllegalArgumentException is expected.
|
||||
new CronExpression("* * * 29 2 *").nextTimeAfter(new DateTime(2012, 3, 1, 00, 00), 1000 * 60 * 60 * 24 * 356 * 2);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue