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:
unknown 2015-07-01 18:55:08 +02:00
parent 3c2006d412
commit b2e7da3170
2 changed files with 47 additions and 0 deletions

View File

@ -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 + ">";

View File

@ -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);
}
}