Skip to content

Commit 0c73901

Browse files
committed
Merge branch '6.2.x'
2 parents 262ce16 + 174d0e4 commit 0c73901

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

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

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -318,8 +318,16 @@ private static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) {
318318
private static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) {
319319
TemporalAdjuster adjuster = TemporalAdjusters.dayOfWeekInMonth(ordinal, dayOfWeek);
320320
return temporal -> {
321-
Temporal result = adjuster.adjustInto(temporal);
322-
return rollbackToMidnight(temporal, result);
321+
// TemporalAdjusters can overflow to a different month
322+
// in this case, attempt the same adjustment with the next/previous month
323+
for (int i = 0; i < 12; i++) {
324+
Temporal result = adjuster.adjustInto(temporal);
325+
if (result.get(ChronoField.MONTH_OF_YEAR) == temporal.get(ChronoField.MONTH_OF_YEAR)) {
326+
return rollbackToMidnight(temporal, result);
327+
}
328+
temporal = result;
329+
}
330+
return null;
323331
};
324332
}
325333

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

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@
3939
import static org.assertj.core.api.Assertions.assertThat;
4040

4141
/**
42+
* Tests for {@link CronExpression}.
4243
* @author Arjen Poutsma
4344
*/
4445
class CronExpressionTests {
@@ -1092,6 +1093,20 @@ void quartz2ndFridayOfTheMonthDayName() {
10921093
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
10931094
}
10941095

1096+
@Test
1097+
void quartz5thMondayOfTheMonthDayName() {
1098+
CronExpression expression = CronExpression.parse("0 0 0 ? * MON#5");
1099+
1100+
LocalDateTime last = LocalDateTime.of(2025, 1, 1, 0, 0, 0);
1101+
1102+
// first occurrence of 5 mondays in a month from last
1103+
LocalDateTime expected = LocalDateTime.of(2025, 3, 31, 0, 0, 0);
1104+
LocalDateTime actual = expression.next(last);
1105+
assertThat(actual).isNotNull();
1106+
assertThat(actual).isEqualTo(expected);
1107+
assertThat(actual.getDayOfWeek()).isEqualTo(MONDAY);
1108+
}
1109+
10951110
@Test
10961111
void quartzFifthWednesdayOfTheMonth() {
10971112
CronExpression expression = CronExpression.parse("0 0 0 ? * 3#5");

0 commit comments

Comments
 (0)