Browse Source

Drop support for standalone "L" in CronExpression

This commit removes support for a standalone "L" in the
day-of-week of a cron expression, which used a locale-dependent
API to determine what the last day of the week is (Saturday or
Sunday ?).
Alternatively, we could have implement this in the exact way as Quartz
has done (i.e. treat the "L" like "SAT"), but we opted not to do that,
as having an explicit SAT or SUN is much clearer.
pull/26336/head
Arjen Poutsma 4 years ago
parent
commit
4d670ee25d
  1. 5
      spring-context/src/main/java/org/springframework/scheduling/support/CronExpression.java
  2. 19
      spring-context/src/main/java/org/springframework/scheduling/support/QuartzCronField.java
  3. 56
      spring-context/src/test/java/org/springframework/scheduling/support/CronExpressionTests.java
  4. 46
      spring-context/src/test/java/org/springframework/scheduling/support/QuartzCronFieldTests.java

5
spring-context/src/main/java/org/springframework/scheduling/support/CronExpression.java

@ -121,9 +121,7 @@ public final class CronExpression { @@ -121,9 +121,7 @@ public final class CronExpression {
* </li>
* <li>
* In the "day of week" field, {@code L} stands for "the last day of the
* week", and uses the
* {@linkplain java.util.Locale#getDefault() system default locale}
* to determine which day that is (i.e. Sunday or Saturday).
* week".
* If prefixed by a number or three-letter name (i.e. {@code dL} or
* {@code DDDL}), it means "the last day of week {@code d} (or {@code DDD})
* in the month".
@ -158,7 +156,6 @@ public final class CronExpression { @@ -158,7 +156,6 @@ public final class CronExpression {
* <li>{@code "0 0 0 L-3 * *"} = third-to-last day of the month at midnight</li>
* <li>{@code "0 0 0 1W * *"} = first weekday of the month at midnight</li>
* <li>{@code "0 0 0 LW * *"} = last weekday of the month at midnight</li>
* <li>{@code "0 0 0 * * L"} = last day of the week at midnight</li>
* <li>{@code "0 0 0 * * 5L"} = last Friday of the month at midnight</li>
* <li>{@code "0 0 0 * * THUL"} = last Thursday of the month at midnight</li>
* <li>{@code "0 0 0 ? * 5#2"} = the second Friday in the month at midnight</li>

19
spring-context/src/main/java/org/springframework/scheduling/support/QuartzCronField.java

@ -23,9 +23,6 @@ import java.time.temporal.ChronoUnit; @@ -23,9 +23,6 @@ import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalField;
import java.time.temporal.WeekFields;
import java.util.Locale;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -140,8 +137,8 @@ final class QuartzCronField extends CronField { @@ -140,8 +137,8 @@ final class QuartzCronField extends CronField {
}
else {
TemporalAdjuster adjuster;
if (idx == 0) { // "L"
adjuster = lastDayOfWeek(Locale.getDefault());
if (idx == 0) {
throw new IllegalArgumentException("No day-of-week before 'L' in '" + value + "'");
}
else { // "[0-7]L"
DayOfWeek dayOfWeek = parseDayOfWeek(value.substring(0, idx));
@ -196,18 +193,6 @@ final class QuartzCronField extends CronField { @@ -196,18 +193,6 @@ final class QuartzCronField extends CronField {
};
}
/**
* Return a temporal adjuster that finds the last day-of-week, depending
* on the given locale.
* @param locale the locale to base the last day calculation on
* @return the last day-of-week adjuster
*/
private static TemporalAdjuster lastDayOfWeek(Locale locale) {
Assert.notNull(locale, "Locale must not be null");
TemporalField dayOfWeek = WeekFields.of(locale).dayOfWeek();
return temporal -> temporal.with(dayOfWeek, 7);
}
/**
* Return a temporal adjuster that finds the weekday nearest to the given
* day-of-month. If {@code dayOfMonth} falls on a Saturday, the date is

56
spring-context/src/test/java/org/springframework/scheduling/support/CronExpressionTests.java

@ -24,14 +24,12 @@ import java.time.ZoneId; @@ -24,14 +24,12 @@ import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
import java.util.Locale;
import org.assertj.core.api.Condition;
import org.junit.jupiter.api.Test;
import static java.time.DayOfWeek.FRIDAY;
import static java.time.DayOfWeek.MONDAY;
import static java.time.DayOfWeek.SATURDAY;
import static java.time.DayOfWeek.SUNDAY;
import static java.time.DayOfWeek.TUESDAY;
import static java.time.DayOfWeek.WEDNESDAY;
@ -736,60 +734,6 @@ class CronExpressionTests { @@ -736,60 +734,6 @@ class CronExpressionTests {
assertThat(actual).is(weekday);
}
@Test
public void quartzLastDayOfWeekFirstDayMonday() {
Locale defaultLocale = Locale.getDefault();
try {
Locale.setDefault(Locale.UK);
CronExpression expression = CronExpression.parse("0 0 0 * * L");
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
LocalDateTime expected = LocalDateTime.of(2008, 1, 6, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY);
last = actual;
expected = expected.plusWeeks(1);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY);
}
finally {
Locale.setDefault(defaultLocale);
}
}
@Test
public void quartzLastDayOfWeekFirstDaySunday() {
Locale defaultLocale = Locale.getDefault();
try {
Locale.setDefault(Locale.US);
CronExpression expression = CronExpression.parse("0 0 0 * * L");
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
LocalDateTime expected = LocalDateTime.of(2008, 1, 5, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SATURDAY);
last = actual;
expected = expected.plusWeeks(1);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SATURDAY);
}
finally {
Locale.setDefault(defaultLocale);
}
}
@Test
public void quartzLastDayOfWeekOffset() {
// last Friday (5) of the month

46
spring-context/src/test/java/org/springframework/scheduling/support/QuartzCronFieldTests.java

@ -18,12 +18,9 @@ package org.springframework.scheduling.support; @@ -18,12 +18,9 @@ package org.springframework.scheduling.support;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import static java.time.DayOfWeek.SATURDAY;
import static java.time.DayOfWeek.SUNDAY;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@ -62,48 +59,6 @@ class QuartzCronFieldTests { @@ -62,48 +59,6 @@ class QuartzCronFieldTests {
assertThat(actual).isEqualTo(expected);
}
@Test
public void lastDayOfWeekFirstDayMonday() {
Locale defaultLocale = Locale.getDefault();
try {
Locale.setDefault(Locale.UK);
QuartzCronField field = QuartzCronField.parseDaysOfWeek("L");
LocalDate last = LocalDate.of(2020, 6, 16);
LocalDate expected = LocalDate.of(2020, 6, 21);
assertThat(field.nextOrSame(last)).isEqualTo(expected);
LocalDate actual = field.nextOrSame(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY);
}
finally {
Locale.setDefault(defaultLocale);
}
}
@Test
public void lastDayOfWeekFirstDaySunday() {
Locale defaultLocale = Locale.getDefault();
try {
Locale.setDefault(Locale.US);
QuartzCronField field = QuartzCronField.parseDaysOfWeek("L");
LocalDate last = LocalDate.of(2020, 6, 16);
LocalDate expected = LocalDate.of(2020, 6, 20);
assertThat(field.nextOrSame(last)).isEqualTo(expected);
LocalDate actual = field.nextOrSame(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SATURDAY);
}
finally {
Locale.setDefault(defaultLocale);
}
}
@Test
void lastDayOfWeekOffset() {
// last Thursday (4) of the month
@ -129,6 +84,7 @@ class QuartzCronFieldTests { @@ -129,6 +84,7 @@ class QuartzCronFieldTests {
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek(""));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("1"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("L"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("L1"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("LL"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("-4L"));

Loading…
Cancel
Save