mirror of
https://github.com/frode-carlsen/cron.git
synced 2025-12-06 14:00:57 +03:00
Separate modules to provide java6/jodatime support and java8/java-time support
This commit is contained in:
474
java8/src/main/java/fc/cron/CronExpression.java
Normal file
474
java8/src/main/java/fc/cron/CronExpression.java
Normal file
@@ -0,0 +1,474 @@
|
||||
package fc.cron;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012- Frode Carlsen.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Note: rewritten to standard Java 8 DateTime by zemiak (c) 2016
|
||||
*/
|
||||
import java.time.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* This provides cron support for java8 using java-time.
|
||||
* <P>
|
||||
*
|
||||
* Parser for unix-like cron expressions: Cron expressions allow specifying combinations of criteria for time
|
||||
* such as: "Each Monday-Friday at 08:00" or "Every last friday of the month at 01:30"
|
||||
* <p>
|
||||
* A cron expressions consists of 5 or 6 mandatory fields (seconds may be omitted) separated by space. <br>
|
||||
* These are:
|
||||
*
|
||||
* <table cellspacing="8">
|
||||
* <tr>
|
||||
* <th align="left">Field</th>
|
||||
* <th align="left"> </th>
|
||||
* <th align="left">Allowable values</th>
|
||||
* <th align="left"> </th>
|
||||
* <th align="left">Special Characters</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left"><code>Seconds (may be omitted)</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>0-59</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>, - * /</code></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left"><code>Minutes</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>0-59</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>, - * /</code></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left"><code>Hours</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>0-23</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>, - * /</code></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left"><code>Day of month</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>1-31</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>, - * ? / L W</code></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left"><code>Month</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>1-12 or JAN-DEC (note: english abbreviations)</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>, - * /</code></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left"><code>Day of week</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>1-7 or MON-SUN (note: english abbreviations)</code></td>
|
||||
* <td align="left"> </th>
|
||||
* <td align="left"><code>, - * ? / L #</code></td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <P>
|
||||
* '*' Can be used in all fields and means 'for all values'. E.g. "*" in minutes, means 'for all minutes'
|
||||
* <P>
|
||||
* '?' Can be used in Day-of-month and Day-of-week fields. Used to signify 'no special value'. It is used when one want
|
||||
* to specify something for one of those two fields, but not the other.
|
||||
* <P>
|
||||
* '-' Used to specify a time interval. E.g. "10-12" in Hours field means 'for hours 10, 11 and 12'
|
||||
* <P>
|
||||
* ',' Used to specify multiple values for a field. E.g. "MON,WED,FRI" in Day-of-week field means "for
|
||||
* monday, wednesday and friday"
|
||||
* <P>
|
||||
* '/' Used to specify increments. E.g. "0/15" in Seconds field means "for seconds 0, 15, 30, ad
|
||||
* 45". And "5/15" in seconds field means "for seconds 5, 20, 35, and 50". If '*' s specified
|
||||
* before '/' it is the same as saying it starts at 0. For every field there's a list of values that can be turned on or
|
||||
* off. For Seconds and Minutes these range from 0-59. For Hours from 0 to 23, For Day-of-month it's 1 to 31, For Months
|
||||
* 1 to 12. "/" character helsp turn some of these values back on. Thus "7/6" in Months field
|
||||
* specify just Month 7. It doesn't turn on every 6 month following, since cron fields never roll over
|
||||
* <P>
|
||||
* 'L' Can be used on Day-of-month and Day-of-week fields. It signifies last day of the set of allowed values. In
|
||||
* Day-of-month field it's the last day of the month (e.g.. 31 jan, 28 feb (29 in leap years), 31 march, etc.). In
|
||||
* Day-of-week field it's Sunday. If there's a prefix, this will be subtracted (5L in Day-of-month means 5 days before
|
||||
* last day of Month: 26 jan, 23 feb, etc.)
|
||||
* <P>
|
||||
* 'W' Can be specified in Day-of-Month field. It specifies closest weekday (monday-friday). Holidays are not accounted
|
||||
* for. "15W" in Day-of-Month field means 'closest weekday to 15 i in given month'. If the 15th is a Saturday,
|
||||
* it gives Friday. If 15th is a Sunday, the it gives following Monday.
|
||||
* <P>
|
||||
* '#' Can be used in Day-of-Week field. For example: "5#3" means 'third friday in month' (day 5 = friday, #3
|
||||
* - the third). If the day does not exist (e.g. "5#5" - 5th friday of month) and there aren't 5 fridays in
|
||||
* the month, then it won't match until the next month with 5 fridays.
|
||||
* <P>
|
||||
* <b>Case-sensitive</b> No fields are case-sensitive
|
||||
* <P>
|
||||
* <b>Dependencies between fields</b> Fields are always evaluated independently, but the expression doesn't match until
|
||||
* the constraints of each field are met. Overlap of intervals are not allowed. That is: for
|
||||
* Day-of-week field "FRI-MON" is invalid,but "FRI-SUN,MON" is valid
|
||||
*
|
||||
*/
|
||||
public class CronExpression {
|
||||
|
||||
enum CronFieldType {
|
||||
SECOND(0, 59, null), MINUTE(0, 59, null), HOUR(0, 23, null), DAY_OF_MONTH(1, 31, null), MONTH(1, 12,
|
||||
Arrays.asList("JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC")), DAY_OF_WEEK(1, 7,
|
||||
Arrays.asList("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"));
|
||||
|
||||
final int from, to;
|
||||
final List<String> names;
|
||||
|
||||
CronFieldType(int from, int to, List<String> names) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.names = names;
|
||||
}
|
||||
}
|
||||
|
||||
private final String expr;
|
||||
private final SimpleField secondField;
|
||||
private final SimpleField minuteField;
|
||||
private final SimpleField hourField;
|
||||
private final DayOfWeekField dayOfWeekField;
|
||||
private final SimpleField monthField;
|
||||
private final DayOfMonthField dayOfMonthField;
|
||||
|
||||
public CronExpression(final String expr) {
|
||||
this(expr, true);
|
||||
}
|
||||
|
||||
public CronExpression(final String expr, final boolean withSeconds) {
|
||||
if (expr == null) {
|
||||
throw new IllegalArgumentException("expr is null"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
this.expr = expr;
|
||||
|
||||
final int expectedParts = withSeconds ? 6 : 5;
|
||||
final String[] parts = expr.split("\\s+"); //$NON-NLS-1$
|
||||
if (parts.length != expectedParts) {
|
||||
throw new IllegalArgumentException(String.format("Invalid cron expression [%s], expected %s field, got %s", expr, expectedParts, parts.length));
|
||||
}
|
||||
|
||||
int ix = withSeconds ? 1 : 0;
|
||||
this.secondField = new SimpleField(CronFieldType.SECOND, withSeconds ? parts[0] : "0");
|
||||
this.minuteField = new SimpleField(CronFieldType.MINUTE, parts[ix++]);
|
||||
this.hourField = new SimpleField(CronFieldType.HOUR, parts[ix++]);
|
||||
this.dayOfMonthField = new DayOfMonthField(parts[ix++]);
|
||||
this.monthField = new SimpleField(CronFieldType.MONTH, parts[ix++]);
|
||||
this.dayOfWeekField = new DayOfWeekField(parts[ix++]);
|
||||
}
|
||||
|
||||
public static CronExpression create(final String expr) {
|
||||
return new CronExpression(expr, true);
|
||||
}
|
||||
|
||||
public static CronExpression createWithoutSeconds(final String expr) {
|
||||
return new CronExpression(expr, false);
|
||||
}
|
||||
|
||||
public ZonedDateTime nextTimeAfter(ZonedDateTime 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 ZonedDateTime nextTimeAfter(ZonedDateTime 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(Duration.ofMillis(durationInMillis)));
|
||||
}
|
||||
|
||||
public ZonedDateTime nextTimeAfter(ZonedDateTime afterTime, ZonedDateTime dateTimeBarrier) {
|
||||
ZonedDateTime nextTime = ZonedDateTime.from(afterTime).withNano(0).plusSeconds(1).withNano(0);
|
||||
;
|
||||
|
||||
while (true) { // day of week
|
||||
while (true) { // month
|
||||
while (true) { // day of month
|
||||
while (true) { // hour
|
||||
while (true) { // minute
|
||||
while (true) { // second
|
||||
if (secondField.matches(nextTime.getSecond())) {
|
||||
break;
|
||||
}
|
||||
nextTime = nextTime.plusSeconds(1).withNano(0);
|
||||
}
|
||||
if (minuteField.matches(nextTime.getMinute())) {
|
||||
break;
|
||||
}
|
||||
nextTime = nextTime.plusMinutes(1).withSecond(0).withNano(0);
|
||||
}
|
||||
if (hourField.matches(nextTime.getHour())) {
|
||||
break;
|
||||
}
|
||||
nextTime = nextTime.plusHours(1).withMinute(0).withSecond(0).withNano(0);
|
||||
}
|
||||
if (dayOfMonthField.matches(nextTime.toLocalDate())) {
|
||||
break;
|
||||
}
|
||||
nextTime = nextTime.plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
checkIfDateTimeBarrierIsReached(nextTime, dateTimeBarrier);
|
||||
}
|
||||
if (monthField.matches(nextTime.getMonth().getValue())) {
|
||||
break;
|
||||
}
|
||||
nextTime = nextTime.plusMonths(1).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
checkIfDateTimeBarrierIsReached(nextTime, dateTimeBarrier);
|
||||
}
|
||||
if (dayOfWeekField.matches(nextTime.toLocalDate())) {
|
||||
break;
|
||||
}
|
||||
nextTime = nextTime.plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
checkIfDateTimeBarrierIsReached(nextTime, dateTimeBarrier);
|
||||
}
|
||||
|
||||
return nextTime;
|
||||
}
|
||||
|
||||
private static void checkIfDateTimeBarrierIsReached(ZonedDateTime nextTime, ZonedDateTime 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 + ">";
|
||||
}
|
||||
|
||||
static class FieldPart {
|
||||
private Integer from, to, increment;
|
||||
private String modifier, incrementModifier;
|
||||
}
|
||||
|
||||
abstract static class BasicField {
|
||||
private static final Pattern CRON_FIELD_REGEXP = Pattern
|
||||
.compile("(?: # start of group 1\n"
|
||||
+ " (?:(?<all>\\*)|(?<ignore>\\?)|(?<last>L)) # global flag (L, ?, *)\n"
|
||||
+ " | (?<start>[0-9]{1,2}|[a-z]{3,3}) # or start number or symbol\n"
|
||||
+ " (?: # start of group 2\n"
|
||||
+ " (?<mod>L|W) # modifier (L,W)\n"
|
||||
+ " | -(?<end>[0-9]{1,2}|[a-z]{3,3}) # or end nummer or symbol (in range)\n"
|
||||
+ " )? # end of group 2\n"
|
||||
+ ") # end of group 1\n"
|
||||
+ "(?:(?<incmod>/|\\#)(?<inc>[0-9]{1,7}))? # increment and increment modifier (/ or \\#)\n",
|
||||
Pattern.CASE_INSENSITIVE | Pattern.COMMENTS);
|
||||
|
||||
final CronFieldType fieldType;
|
||||
final List<FieldPart> parts = new ArrayList<>();
|
||||
|
||||
private BasicField(CronFieldType fieldType, String fieldExpr) {
|
||||
this.fieldType = fieldType;
|
||||
parse(fieldExpr);
|
||||
}
|
||||
|
||||
private void parse(String fieldExpr) { // NOSONAR
|
||||
String[] rangeParts = fieldExpr.split(",");
|
||||
for (String rangePart : rangeParts) {
|
||||
Matcher m = CRON_FIELD_REGEXP.matcher(rangePart);
|
||||
if (!m.matches()) {
|
||||
throw new IllegalArgumentException("Invalid cron field '" + rangePart + "' for field [" + fieldType + "]");
|
||||
}
|
||||
String startNummer = m.group("start");
|
||||
String modifier = m.group("mod");
|
||||
String sluttNummer = m.group("end");
|
||||
String incrementModifier = m.group("incmod");
|
||||
String increment = m.group("inc");
|
||||
|
||||
FieldPart part = new FieldPart();
|
||||
part.increment = 999;
|
||||
if (startNummer != null) {
|
||||
part.from = mapValue(startNummer);
|
||||
part.modifier = modifier;
|
||||
if (sluttNummer != null) {
|
||||
part.to = mapValue(sluttNummer);
|
||||
part.increment = 1;
|
||||
} else if (increment != null) {
|
||||
part.to = fieldType.to;
|
||||
} else {
|
||||
part.to = part.from;
|
||||
}
|
||||
} else if (m.group("all") != null) {
|
||||
part.from = fieldType.from;
|
||||
part.to = fieldType.to;
|
||||
part.increment = 1;
|
||||
} else if (m.group("ignore") != null) {
|
||||
part.modifier = m.group("ignore");
|
||||
} else if (m.group("last") != null) {
|
||||
part.modifier = m.group("last");
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid cron part: " + rangePart);
|
||||
}
|
||||
|
||||
if (increment != null) {
|
||||
part.incrementModifier = incrementModifier;
|
||||
part.increment = Integer.valueOf(increment);
|
||||
}
|
||||
|
||||
validateRange(part);
|
||||
validatePart(part);
|
||||
parts.add(part);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected void validatePart(FieldPart part) {
|
||||
if (part.modifier != null) {
|
||||
throw new IllegalArgumentException(String.format("Invalid modifier [%s]", part.modifier));
|
||||
} else if (part.incrementModifier != null && !"/".equals(part.incrementModifier)) {
|
||||
throw new IllegalArgumentException(String.format("Invalid increment modifier [%s]", part.incrementModifier));
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRange(FieldPart part) {
|
||||
if ((part.from != null && part.from < fieldType.from) || (part.to != null && part.to > fieldType.to)) {
|
||||
throw new IllegalArgumentException(String.format("Invalid interval [%s-%s], must be %s<=_<=%s", part.from, part.to, fieldType.from,
|
||||
fieldType.to));
|
||||
} else if (part.from != null && part.to != null && part.from > part.to) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Invalid interval [%s-%s]. Rolling periods are not supported (ex. 5-1, only 1-5) since this won't give a deterministic result. Must be %s<=_<=%s",
|
||||
part.from, part.to, fieldType.from, fieldType.to));
|
||||
}
|
||||
}
|
||||
|
||||
protected Integer mapValue(String value) {
|
||||
Integer idx;
|
||||
if (fieldType.names != null && (idx = fieldType.names.indexOf(value.toUpperCase(Locale.getDefault()))) >= 0) {
|
||||
return idx + 1;
|
||||
}
|
||||
return Integer.valueOf(value);
|
||||
}
|
||||
|
||||
protected boolean matches(int val, FieldPart part) {
|
||||
if (val >= part.from && val <= part.to && (val - part.from) % part.increment == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static class SimpleField extends BasicField {
|
||||
SimpleField(CronFieldType fieldType, String fieldExpr) {
|
||||
super(fieldType, fieldExpr);
|
||||
}
|
||||
|
||||
public boolean matches(int val) {
|
||||
if (val >= fieldType.from && val <= fieldType.to) {
|
||||
for (FieldPart part : parts) {
|
||||
if (matches(val, part)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static class DayOfWeekField extends BasicField {
|
||||
|
||||
DayOfWeekField(String fieldExpr) {
|
||||
super(CronFieldType.DAY_OF_WEEK, fieldExpr);
|
||||
}
|
||||
|
||||
boolean matches(LocalDate dato) {
|
||||
for (FieldPart part : parts) {
|
||||
if ("L".equals(part.modifier)) {
|
||||
YearMonth ym = YearMonth.of(dato.getYear(), dato.getMonth().getValue());
|
||||
return dato.getDayOfWeek() == DayOfWeek.of(part.from) && dato.getDayOfMonth() > (ym.lengthOfMonth() - 7);
|
||||
} else if ("#".equals(part.incrementModifier)) {
|
||||
if (dato.getDayOfWeek() == DayOfWeek.of(part.from)) {
|
||||
int num = dato.getDayOfMonth() / 7;
|
||||
return part.increment == (dato.getDayOfMonth() % 7 == 0 ? num : num + 1);
|
||||
}
|
||||
return false;
|
||||
} else if (matches(dato.getDayOfWeek().getValue(), part)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer mapValue(String value) {
|
||||
// Use 1-7 for weedays, but 0 will also represent sunday (linux practice)
|
||||
return "0".equals(value) ? Integer.valueOf(7) : super.mapValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matches(int val, FieldPart part) {
|
||||
return "?".equals(part.modifier) || super.matches(val, part);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validatePart(FieldPart part) {
|
||||
if (part.modifier != null && Arrays.asList("L", "?").indexOf(part.modifier) == -1) {
|
||||
throw new IllegalArgumentException(String.format("Invalid modifier [%s]", part.modifier));
|
||||
} else if (part.incrementModifier != null && Arrays.asList("/", "#").indexOf(part.incrementModifier) == -1) {
|
||||
throw new IllegalArgumentException(String.format("Invalid increment modifier [%s]", part.incrementModifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class DayOfMonthField extends BasicField {
|
||||
DayOfMonthField(String fieldExpr) {
|
||||
super(CronFieldType.DAY_OF_MONTH, fieldExpr);
|
||||
}
|
||||
|
||||
boolean matches(LocalDate dato) {
|
||||
for (FieldPart part : parts) {
|
||||
if ("L".equals(part.modifier)) {
|
||||
YearMonth ym = YearMonth.of(dato.getYear(), dato.getMonth().getValue());
|
||||
return dato.getDayOfMonth() == (ym.lengthOfMonth() - (part.from == null ? 0 : part.from));
|
||||
} else if ("W".equals(part.modifier)) {
|
||||
if (dato.getDayOfWeek().getValue() <= 5) {
|
||||
if (dato.getDayOfMonth() == part.from) {
|
||||
return true;
|
||||
} else if (dato.getDayOfWeek().getValue() == 5) {
|
||||
return dato.plusDays(1).getDayOfMonth() == part.from;
|
||||
} else if (dato.getDayOfWeek().getValue() == 1) {
|
||||
return dato.minusDays(1).getDayOfMonth() == part.from;
|
||||
}
|
||||
}
|
||||
} else if (matches(dato.getDayOfMonth(), part)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validatePart(FieldPart part) {
|
||||
if (part.modifier != null && Arrays.asList("L", "W", "?").indexOf(part.modifier) == -1) {
|
||||
throw new IllegalArgumentException(String.format("Invalid modifier [%s]", part.modifier));
|
||||
} else if (part.incrementModifier != null && !"/".equals(part.incrementModifier)) {
|
||||
throw new IllegalArgumentException(String.format("Invalid increment modifier [%s]", part.incrementModifier));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matches(int val, FieldPart part) {
|
||||
return "?".equals(part.modifier) || super.matches(val, part);
|
||||
}
|
||||
}
|
||||
}
|
||||
826
java8/src/test/java/fc/cron/CronExpressionTest.java
Normal file
826
java8/src/test/java/fc/cron/CronExpressionTest.java
Normal file
@@ -0,0 +1,826 @@
|
||||
/*
|
||||
* Copyright (C) 2012- Frode Carlsen
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package fc.cron;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.YearMonth;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import fc.cron.CronExpression.CronFieldType;
|
||||
import fc.cron.CronExpression.DayOfMonthField;
|
||||
import fc.cron.CronExpression.DayOfWeekField;
|
||||
import fc.cron.CronExpression.SimpleField;
|
||||
|
||||
public class CronExpressionTest {
|
||||
TimeZone original;
|
||||
ZoneId zoneId;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
original = TimeZone.getDefault();
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
zoneId = TimeZone.getDefault().toZoneId();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
TimeZone.setDefault(original);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shall_parse_number() throws Exception {
|
||||
SimpleField field = new SimpleField(CronFieldType.MINUTE, "5");
|
||||
assertPossibleValues(field, 5);
|
||||
}
|
||||
|
||||
private void assertPossibleValues(SimpleField field, Integer... values) {
|
||||
Set<Integer> valid = values == null ? new HashSet<Integer>() : new HashSet<>(Arrays.asList(values));
|
||||
for (int i = field.fieldType.from; i <= field.fieldType.to; i++) {
|
||||
String errorText = i + ":" + valid;
|
||||
if (valid.contains(i)) {
|
||||
assertTrue(errorText, field.matches(i));
|
||||
} else {
|
||||
assertFalse(errorText, field.matches(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shall_parse_number_with_increment() throws Exception {
|
||||
SimpleField field = new SimpleField(CronFieldType.MINUTE, "0/15");
|
||||
assertPossibleValues(field, 0, 15, 30, 45);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shall_parse_range() throws Exception {
|
||||
SimpleField field = new SimpleField(CronFieldType.MINUTE, "5-10");
|
||||
assertPossibleValues(field, 5, 6, 7, 8, 9, 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shall_parse_range_with_increment() throws Exception {
|
||||
SimpleField field = new SimpleField(CronFieldType.MINUTE, "20-30/2");
|
||||
assertPossibleValues(field, 20, 22, 24, 26, 28, 30);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shall_parse_asterix() throws Exception {
|
||||
SimpleField field = new SimpleField(CronFieldType.DAY_OF_WEEK, "*");
|
||||
assertPossibleValues(field, 1, 2, 3, 4, 5, 6, 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shall_parse_asterix_with_increment() throws Exception {
|
||||
SimpleField field = new SimpleField(CronFieldType.DAY_OF_WEEK, "*/2");
|
||||
assertPossibleValues(field, 1, 3, 5, 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shall_ignore_field_in_day_of_week() throws Exception {
|
||||
DayOfWeekField field = new DayOfWeekField("?");
|
||||
assertTrue("day of week is ?", field.matches(ZonedDateTime.now().toLocalDate()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shall_ignore_field_in_day_of_month() throws Exception {
|
||||
DayOfMonthField field = new DayOfMonthField("?");
|
||||
assertTrue("day of month is ?", field.matches(ZonedDateTime.now().toLocalDate()));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shall_give_error_if_invalid_count_field() throws Exception {
|
||||
new CronExpression("* 3 *");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shall_give_error_if_minute_field_ignored() throws Exception {
|
||||
SimpleField field = new SimpleField(CronFieldType.MINUTE, "?");
|
||||
field.matches(1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shall_give_error_if_hour_field_ignored() throws Exception {
|
||||
SimpleField field = new SimpleField(CronFieldType.HOUR, "?");
|
||||
field.matches(1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shall_give_error_if_month_field_ignored() throws Exception {
|
||||
SimpleField field = new SimpleField(CronFieldType.MONTH, "?");
|
||||
field.matches(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shall_give_last_day_of_month_in_leapyear() throws Exception {
|
||||
CronExpression.DayOfMonthField field = new DayOfMonthField("L");
|
||||
assertTrue("day of month is L", field.matches(LocalDate.of(2012, 02, 29)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shall_give_last_day_of_month() throws Exception {
|
||||
CronExpression.DayOfMonthField field = new DayOfMonthField("L");
|
||||
YearMonth now = YearMonth.now();
|
||||
assertTrue("L matches to the last day of month", field.matches(LocalDate.of(now.getYear(), now.getMonthValue(), now.lengthOfMonth())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_all() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("* * * * * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 1, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 10, 13, 0, 2, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 2, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 2, 1, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 59, 59, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 14, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void check_invalid_input() throws Exception {
|
||||
new CronExpression(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_second_number() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("3 * * * * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 1, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 10, 13, 1, 3, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 1, 3, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 2, 3, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 59, 3, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 14, 0, 3, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 23, 59, 3, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 11, 0, 0, 3, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 30, 23, 59, 3, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 5, 1, 0, 0, 3, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_second_increment() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("5/15 * * * * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 10, 13, 0, 5, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 0, 5, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 0, 20, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 0, 20, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 0, 35, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 0, 35, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 0, 50, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 0, 50, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 1, 5, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
// if rolling over minute then reset second (cron rules - increment affects only values in own field)
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 0, 50, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 1, 10, 0, zoneId);
|
||||
assertTrue(new CronExpression("10/100 * * * * *").nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 1, 10, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 2, 10, 0, zoneId);
|
||||
assertTrue(new CronExpression("10/100 * * * * *").nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_second_list() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("7,19 * * * * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 10, 13, 0, 7, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 0, 7, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 0, 19, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 0, 19, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 1, 7, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_second_range() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("42-45 * * * * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 10, 13, 0, 42, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 0, 42, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 0, 43, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 0, 43, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 0, 44, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 0, 44, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 0, 45, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 0, 45, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 1, 42, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void check_second_invalid_range() throws Exception {
|
||||
new CronExpression("42-63 * * * * *");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void check_second_invalid_increment_modifier() throws Exception {
|
||||
new CronExpression("42#3 * * * * *");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_minute_number() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 3 * * * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 1, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 10, 13, 3, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 3, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 14, 3, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_minute_increment() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0/15 * * * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 10, 13, 15, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 15, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 30, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 30, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 45, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 45, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 14, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_minute_list() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 7,19 * * * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 10, 13, 7, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 13, 7, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 13, 19, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_hour_number() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 * 3 * * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 1, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 11, 3, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 11, 3, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 11, 3, 1, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 11, 3, 59, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 12, 3, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_hour_increment() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 * 0/15 * * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 10, 15, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 15, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 15, 1, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 15, 59, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 11, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 11, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 11, 0, 1, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 11, 15, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 11, 15, 1, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_hour_list() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 * 7,19 * * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 10, 19, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 19, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 10, 19, 1, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 10, 19, 59, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 11, 7, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_hour_shall_run_25_times_in_DST_change_to_wintertime() throws Exception {
|
||||
CronExpression cron = new CronExpression("0 1 * * * *");
|
||||
ZonedDateTime start = ZonedDateTime.of(2011, 10, 30, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime slutt = start.plusDays(1);
|
||||
ZonedDateTime tid = start;
|
||||
|
||||
// throws: Unsupported unit: Seconds
|
||||
// assertEquals(25, Duration.between(start.toLocalDate(), slutt.toLocalDate()).toHours());
|
||||
|
||||
int count = 0;
|
||||
ZonedDateTime lastTime = tid;
|
||||
while (tid.isBefore(slutt)){
|
||||
ZonedDateTime nextTime = cron.nextTimeAfter(tid);
|
||||
assertTrue(nextTime.isAfter(lastTime));
|
||||
lastTime = nextTime;
|
||||
tid = tid.plusHours(1);
|
||||
count++;
|
||||
}
|
||||
assertEquals(25, count);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_hour_shall_run_23_times_in_DST_change_to_summertime() throws Exception {
|
||||
CronExpression cron = new CronExpression("0 0 * * * *");
|
||||
ZonedDateTime start = ZonedDateTime.of(2011, 03, 27, 1, 0, 0, 0, zoneId);
|
||||
ZonedDateTime slutt = start.plusDays(1);
|
||||
ZonedDateTime tid = start;
|
||||
|
||||
// throws: Unsupported unit: Seconds
|
||||
// assertEquals(23, Duration.between(start.toLocalDate(), slutt.toLocalDate()).toHours());
|
||||
|
||||
int count=0;
|
||||
ZonedDateTime lastTime = tid;
|
||||
while(tid.isBefore(slutt)){
|
||||
ZonedDateTime nextTime = cron.nextTimeAfter(tid);
|
||||
assertTrue(nextTime.isAfter(lastTime));
|
||||
lastTime = nextTime;
|
||||
tid = tid.plusHours(1);
|
||||
count++;
|
||||
}
|
||||
assertEquals(23, count);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfMonth_number() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 * * 3 * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 5, 3, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 5, 3, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 5, 3, 0, 1, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 5, 3, 0, 59, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 5, 3, 1, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 5, 3, 23, 59, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 6, 3, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfMonth_increment() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 1/15 * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 16, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 16, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 5, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 30, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 5, 1, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 5, 16, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfMonth_list() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 7,19 * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 19, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 19, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 5, 7, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 5, 7, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 5, 19, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 5, 30, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 6, 7, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfMonth_last() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 L * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 30, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 2, 12, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 2, 29, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfMonth_number_last_L() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 3L * *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 10, 13, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 30 - 3, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 2, 12, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 2, 29 - 3, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfMonth_closest_weekday_W() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 9W * *");
|
||||
|
||||
// 9 - is weekday in may
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 5, 2, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 5, 9, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
// 9 - is weekday in may
|
||||
after = ZonedDateTime.of(2012, 5, 8, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
// 9 - saturday, friday closest weekday in june
|
||||
after = ZonedDateTime.of(2012, 5, 9, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 6, 8, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
// 9 - sunday, monday closest weekday in september
|
||||
after = ZonedDateTime.of(2012, 9, 1, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 9, 10, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void check_dayOfMonth_invalid_modifier() throws Exception {
|
||||
new CronExpression("0 0 0 9X * *");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void check_dayOfMonth_invalid_increment_modifier() throws Exception {
|
||||
new CronExpression("0 0 0 9#2 * *");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_month_number() throws Exception {
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 2, 12, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 5, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 1 5 *").nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_month_increment() throws Exception {
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 2, 12, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 5, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 1 5/2 *").nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 5, 1, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 7, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 1 5/2 *").nextTimeAfter(after).equals(expected));
|
||||
|
||||
// if rolling over year then reset month field (cron rules - increments only affect own field)
|
||||
after = ZonedDateTime.of(2012, 5, 1, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2013, 5, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 1 5/10 *").nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_month_list() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 1 3,7,12 *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 2, 12, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 3, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 3, 1, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 7, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 7, 1, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 12, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_month_list_by_name() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 1 MAR,JUL,DEC *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 2, 12, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 3, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 3, 1, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 7, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 7, 1, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 12, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void check_month_invalid_modifier() throws Exception {
|
||||
new CronExpression("0 0 0 1 ? *");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfWeek_number() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 * * 3");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 1, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 4, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 4, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 11, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 12, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 18, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 18, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 25, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfWeek_increment() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 * * 3/2");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 1, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 4, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 4, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 6, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 6, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 8, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 8, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 11, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfWeek_list() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 * * 1,5,7");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 1, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 2, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 2, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 6, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 6, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 8, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfWeek_list_by_name() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 * * MON,FRI,SUN");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 1, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 2, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 2, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 6, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 6, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 8, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfWeek_last_friday_in_month() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("0 0 0 * * 5L");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 1, 1, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 27, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 27, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 5, 25, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 2, 6, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 2, 24, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 2, 6, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 2, 24, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * FRIL").nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void check_dayOfWeek_invalid_modifier() throws Exception {
|
||||
new CronExpression("0 0 0 * * 5W");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void check_dayOfWeek_invalid_increment_modifier() throws Exception {
|
||||
new CronExpression("0 0 0 * * 5?3");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfWeek_shall_interpret_0_as_sunday() throws Exception {
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 1, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 8, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * 0").nextTimeAfter(after).equals(expected));
|
||||
|
||||
expected = ZonedDateTime.of(2012, 4, 29, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * 0L").nextTimeAfter(after).equals(expected));
|
||||
|
||||
expected = ZonedDateTime.of(2012, 4, 8, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * 0#2").nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfWeek_shall_interpret_7_as_sunday() throws Exception {
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 1, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 8, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * 7").nextTimeAfter(after).equals(expected));
|
||||
|
||||
expected = ZonedDateTime.of(2012, 4, 29, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * 7L").nextTimeAfter(after).equals(expected));
|
||||
|
||||
expected = ZonedDateTime.of(2012, 4, 8, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * 7#2").nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void check_dayOfWeek_nth_day_in_month() throws Exception {
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 4, 1, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2012, 4, 20, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * 5#3").nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 20, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 5, 18, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * 5#3").nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 3, 30, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 4, 1, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * 7#1").nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 4, 1, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 5, 6, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * 7#1").nextTimeAfter(after).equals(expected));
|
||||
|
||||
after = ZonedDateTime.of(2012, 2, 6, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 2, 29, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * 3#5").nextTimeAfter(after).equals(expected)); // leapday
|
||||
|
||||
after = ZonedDateTime.of(2012, 2, 6, 0, 0, 0, 0, zoneId);
|
||||
expected = ZonedDateTime.of(2012, 2, 29, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(new CronExpression("0 0 0 * * WED#5").nextTimeAfter(after).equals(expected)); // leapday
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
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(ZonedDateTime.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_default_barrier() throws Exception {
|
||||
CronExpression cronExpr = new CronExpression("* * * 29 2 *");
|
||||
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 3, 1, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2016, 2, 29, 0, 0, 0, 0, zoneId);
|
||||
// the default barrier is 4 years - so leap years are considered.
|
||||
assertTrue(cronExpr.nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void test_one_year_barrier() throws Exception {
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 3, 1, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime barrier = ZonedDateTime.of(2013, 3, 1, 0, 0, 0, 0, zoneId);
|
||||
// The next leap year is 2016, so an IllegalArgumentException is expected.
|
||||
new CronExpression("* * * 29 2 *").nextTimeAfter(after, barrier);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void test_two_year_barrier() throws Exception {
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 3, 1, 0, 0, 0, 0, zoneId);
|
||||
// The next leap year is 2016, so an IllegalArgumentException is expected.
|
||||
new CronExpression("* * * 29 2 *").nextTimeAfter(after, 1000 * 60 * 60 * 24 * 356 * 2);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void test_seconds_specified_but_should_be_omitted() throws Exception {
|
||||
CronExpression.createWithoutSeconds("* * * 29 2 *");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_without_seconds() throws Exception {
|
||||
ZonedDateTime after = ZonedDateTime.of(2012, 3, 1, 0, 0, 0, 0, zoneId);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2016, 2, 29, 0, 0, 0, 0, zoneId);
|
||||
assertTrue(CronExpression.createWithoutSeconds("* * 29 2 *").nextTimeAfter(after).equals(expected));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user