From c20b56923e289518b319837b2b9857970a010a64 Mon Sep 17 00:00:00 2001 From: Jialin Chen Date: Sat, 24 Oct 2026 02:23:41 +0800 Subject: [PATCH] Fix SUN-SUN day-of-week range in CronExpression Prior to this commit, a day-of-week range that starts and ends with Sunday, such as `SUN-SUN` or `7-7`, matched every day of the week. Since gh-26598, a range minimum of 7 is turned into 0 so that ranges like `SUN-FRI` are supported, but that also turned `7-7` into `0-7`. This commit only applies that conversion if the range does not end with Sunday as well, so that `SUN-SUN` matches Sundays only, as `SUN`, `7` and `0-0` already do. Signed-off-by: Jialin Chen --- .../scheduling/support/BitsCronField.java | 5 +++-- .../support/BitsCronFieldTests.java | 1 + .../support/CronExpressionTests.java | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/scheduling/support/BitsCronField.java b/spring-context/src/main/java/org/springframework/scheduling/support/BitsCronField.java index 9af70129bd05..659dcb5740df 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/support/BitsCronField.java +++ b/spring-context/src/main/java/org/springframework/scheduling/support/BitsCronField.java @@ -161,8 +161,9 @@ private static ValueRange parseRange(String value, Type type) { int max = Integer.parseInt(value, hyphenPos + 1, value.length(), 10); min = type.checkValidValue(min); max = type.checkValidValue(max); - if (type == Type.DAY_OF_WEEK && min == 7) { - // If used as a minimum in a range, Sunday means 0 (not 7) + if (type == Type.DAY_OF_WEEK && min == 7 && max != 7) { + // If used as a minimum in a range, Sunday means 0 (not 7), + // unless the range also ends with Sunday, as in "SUN-SUN" min = 0; } return ValueRange.of(min, max); diff --git a/spring-context/src/test/java/org/springframework/scheduling/support/BitsCronFieldTests.java b/spring-context/src/test/java/org/springframework/scheduling/support/BitsCronFieldTests.java index 7361054fc3ec..989e8085dfcf 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/support/BitsCronFieldTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/support/BitsCronFieldTests.java @@ -55,6 +55,7 @@ void parse() { assertThat(BitsCronField.parseDaysOfWeek("0")).has(set(7, 7)).has(clearRange(0, 6)); assertThat(BitsCronField.parseDaysOfWeek("7-5")).has(clear(0)).has(setRange(1, 5)) .has(clear(6)).has(set(7)); + assertThat(BitsCronField.parseDaysOfWeek("7-7")).has(clearRange(0, 6)).has(set(7)); } @Test diff --git a/spring-context/src/test/java/org/springframework/scheduling/support/CronExpressionTests.java b/spring-context/src/test/java/org/springframework/scheduling/support/CronExpressionTests.java index c35abbee6541..651d0e4b0e18 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/support/CronExpressionTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/support/CronExpressionTests.java @@ -1328,6 +1328,25 @@ void sundayToFriday() { assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY); } + @Test + void sundayToSunday() { + CronExpression expression = CronExpression.parse("0 0 0 ? * SUN-SUN"); + + LocalDateTime last = LocalDateTime.of(2021, 2, 25, 15, 0); + LocalDateTime expected = LocalDateTime.of(2021, 2, 28, 0, 0); + LocalDateTime actual = expression.next(last); + assertThat(actual).isNotNull(); + assertThat(actual).isEqualTo(expected); + assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY); + + last = actual; + expected = LocalDateTime.of(2021, 3, 7, 0, 0); + actual = expression.next(last); + assertThat(actual).isNotNull(); + assertThat(actual).isEqualTo(expected); + assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY); + } + @Test void daylightSaving() { CronExpression cronExpression = CronExpression.parse("0 0 9 * * *");