Skip to content

Commit 4d670ee

Browse files
committed
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.
1 parent 762cf0f commit 4d670ee

File tree

4 files changed

+4
-122
lines changed

4 files changed

+4
-122
lines changed

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,7 @@ private CronExpression(
121121
* </li>
122122
* <li>
123123
* In the "day of week" field, {@code L} stands for "the last day of the
124-
* week", and uses the
125-
* {@linkplain java.util.Locale#getDefault() system default locale}
126-
* to determine which day that is (i.e. Sunday or Saturday).
124+
* week".
127125
* If prefixed by a number or three-letter name (i.e. {@code dL} or
128126
* {@code DDDL}), it means "the last day of week {@code d} (or {@code DDD})
129127
* in the month".
@@ -158,7 +156,6 @@ private CronExpression(
158156
* <li>{@code "0 0 0 L-3 * *"} = third-to-last day of the month at midnight</li>
159157
* <li>{@code "0 0 0 1W * *"} = first weekday of the month at midnight</li>
160158
* <li>{@code "0 0 0 LW * *"} = last weekday of the month at midnight</li>
161-
* <li>{@code "0 0 0 * * L"} = last day of the week at midnight</li>
162159
* <li>{@code "0 0 0 * * 5L"} = last Friday of the month at midnight</li>
163160
* <li>{@code "0 0 0 * * THUL"} = last Thursday of the month at midnight</li>
164161
* <li>{@code "0 0 0 ? * 5#2"} = the second Friday in the month at midnight</li>

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

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
import java.time.temporal.Temporal;
2424
import java.time.temporal.TemporalAdjuster;
2525
import java.time.temporal.TemporalAdjusters;
26-
import java.time.temporal.TemporalField;
27-
import java.time.temporal.WeekFields;
28-
import java.util.Locale;
2926

3027
import org.springframework.lang.Nullable;
3128
import org.springframework.util.Assert;
@@ -140,8 +137,8 @@ public static QuartzCronField parseDaysOfWeek(String value) {
140137
}
141138
else {
142139
TemporalAdjuster adjuster;
143-
if (idx == 0) { // "L"
144-
adjuster = lastDayOfWeek(Locale.getDefault());
140+
if (idx == 0) {
141+
throw new IllegalArgumentException("No day-of-week before 'L' in '" + value + "'");
145142
}
146143
else { // "[0-7]L"
147144
DayOfWeek dayOfWeek = parseDayOfWeek(value.substring(0, idx));
@@ -196,18 +193,6 @@ private static TemporalAdjuster lastDayWithOffset(int offset) {
196193
};
197194
}
198195

199-
/**
200-
* Return a temporal adjuster that finds the last day-of-week, depending
201-
* on the given locale.
202-
* @param locale the locale to base the last day calculation on
203-
* @return the last day-of-week adjuster
204-
*/
205-
private static TemporalAdjuster lastDayOfWeek(Locale locale) {
206-
Assert.notNull(locale, "Locale must not be null");
207-
TemporalField dayOfWeek = WeekFields.of(locale).dayOfWeek();
208-
return temporal -> temporal.with(dayOfWeek, 7);
209-
}
210-
211196
/**
212197
* Return a temporal adjuster that finds the weekday nearest to the given
213198
* day-of-month. If {@code dayOfMonth} falls on a Saturday, the date is

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

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,12 @@
2424
import java.time.ZonedDateTime;
2525
import java.time.temporal.ChronoField;
2626
import java.time.temporal.Temporal;
27-
import java.util.Locale;
2827

2928
import org.assertj.core.api.Condition;
3029
import org.junit.jupiter.api.Test;
3130

3231
import static java.time.DayOfWeek.FRIDAY;
3332
import static java.time.DayOfWeek.MONDAY;
34-
import static java.time.DayOfWeek.SATURDAY;
3533
import static java.time.DayOfWeek.SUNDAY;
3634
import static java.time.DayOfWeek.TUESDAY;
3735
import static java.time.DayOfWeek.WEDNESDAY;
@@ -736,60 +734,6 @@ void quartzLastWeekdayOfMonth() {
736734
assertThat(actual).is(weekday);
737735
}
738736

739-
@Test
740-
public void quartzLastDayOfWeekFirstDayMonday() {
741-
Locale defaultLocale = Locale.getDefault();
742-
try {
743-
Locale.setDefault(Locale.UK);
744-
745-
CronExpression expression = CronExpression.parse("0 0 0 * * L");
746-
747-
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
748-
LocalDateTime expected = LocalDateTime.of(2008, 1, 6, 0, 0);
749-
LocalDateTime actual = expression.next(last);
750-
assertThat(actual).isNotNull();
751-
assertThat(actual).isEqualTo(expected);
752-
assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY);
753-
754-
last = actual;
755-
expected = expected.plusWeeks(1);
756-
actual = expression.next(last);
757-
assertThat(actual).isNotNull();
758-
assertThat(actual).isEqualTo(expected);
759-
assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY);
760-
}
761-
finally {
762-
Locale.setDefault(defaultLocale);
763-
}
764-
}
765-
766-
@Test
767-
public void quartzLastDayOfWeekFirstDaySunday() {
768-
Locale defaultLocale = Locale.getDefault();
769-
try {
770-
Locale.setDefault(Locale.US);
771-
772-
CronExpression expression = CronExpression.parse("0 0 0 * * L");
773-
774-
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
775-
LocalDateTime expected = LocalDateTime.of(2008, 1, 5, 0, 0);
776-
LocalDateTime actual = expression.next(last);
777-
assertThat(actual).isNotNull();
778-
assertThat(actual).isEqualTo(expected);
779-
assertThat(actual.getDayOfWeek()).isEqualTo(SATURDAY);
780-
781-
last = actual;
782-
expected = expected.plusWeeks(1);
783-
actual = expression.next(last);
784-
assertThat(actual).isNotNull();
785-
assertThat(actual).isEqualTo(expected);
786-
assertThat(actual.getDayOfWeek()).isEqualTo(SATURDAY);
787-
}
788-
finally {
789-
Locale.setDefault(defaultLocale);
790-
}
791-
}
792-
793737
@Test
794738
public void quartzLastDayOfWeekOffset() {
795739
// last Friday (5) of the month

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

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,9 @@
1818

1919
import java.time.DayOfWeek;
2020
import java.time.LocalDate;
21-
import java.util.Locale;
2221

2322
import org.junit.jupiter.api.Test;
2423

25-
import static java.time.DayOfWeek.SATURDAY;
26-
import static java.time.DayOfWeek.SUNDAY;
2724
import static org.assertj.core.api.Assertions.assertThat;
2825
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
2926

@@ -62,48 +59,6 @@ void lastWeekdayOfMonth() {
6259
assertThat(actual).isEqualTo(expected);
6360
}
6461

65-
@Test
66-
public void lastDayOfWeekFirstDayMonday() {
67-
Locale defaultLocale = Locale.getDefault();
68-
try {
69-
Locale.setDefault(Locale.UK);
70-
QuartzCronField field = QuartzCronField.parseDaysOfWeek("L");
71-
72-
LocalDate last = LocalDate.of(2020, 6, 16);
73-
LocalDate expected = LocalDate.of(2020, 6, 21);
74-
assertThat(field.nextOrSame(last)).isEqualTo(expected);
75-
76-
LocalDate actual = field.nextOrSame(last);
77-
assertThat(actual).isNotNull();
78-
assertThat(actual).isEqualTo(expected);
79-
assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY);
80-
}
81-
finally {
82-
Locale.setDefault(defaultLocale);
83-
}
84-
}
85-
86-
@Test
87-
public void lastDayOfWeekFirstDaySunday() {
88-
Locale defaultLocale = Locale.getDefault();
89-
try {
90-
Locale.setDefault(Locale.US);
91-
QuartzCronField field = QuartzCronField.parseDaysOfWeek("L");
92-
93-
LocalDate last = LocalDate.of(2020, 6, 16);
94-
LocalDate expected = LocalDate.of(2020, 6, 20);
95-
assertThat(field.nextOrSame(last)).isEqualTo(expected);
96-
97-
LocalDate actual = field.nextOrSame(last);
98-
assertThat(actual).isNotNull();
99-
assertThat(actual).isEqualTo(expected);
100-
assertThat(actual.getDayOfWeek()).isEqualTo(SATURDAY);
101-
}
102-
finally {
103-
Locale.setDefault(defaultLocale);
104-
}
105-
}
106-
10762
@Test
10863
void lastDayOfWeekOffset() {
10964
// last Thursday (4) of the month
@@ -129,6 +84,7 @@ void invalidValues() {
12984

13085
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek(""));
13186
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("1"));
87+
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("L"));
13288
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("L1"));
13389
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("LL"));
13490
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("-4L"));

0 commit comments

Comments
 (0)