From 7276752e7cbc87aead678ae84ec8a83e7603a141 Mon Sep 17 00:00:00 2001 From: vikey Date: Sat, 12 Feb 2022 18:51:24 +0800 Subject: [PATCH 1/2] Fix CronExpression issue with DST This commit fixes an issue with CronExpression fails to calculate next execution on the day of daylight saving time. Closes gh-28038 --- .../springframework/scheduling/support/CronField.java | 9 +++++++-- .../scheduling/support/CronExpressionTests.java | 8 ++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/scheduling/support/CronField.java b/spring-context/src/main/java/org/springframework/scheduling/support/CronField.java index bed95066345..e01e00b6322 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/support/CronField.java +++ b/spring-context/src/main/java/org/springframework/scheduling/support/CronField.java @@ -260,7 +260,7 @@ abstract class CronField { * Roll forward the give temporal until it reaches the next higher * order field. Calling this method is equivalent to calling * {@link #elapseUntil(Temporal, int)} with goal set to the - * minimum value of this field's range. + * minimum value of this field's range, except for daylight saving. * @param temporal the temporal to roll forward * @param the type of temporal * @return the rolled forward temporal @@ -269,7 +269,12 @@ abstract class CronField { int current = get(temporal); ValueRange range = temporal.range(this.field); long amount = range.getMaximum() - current + 1; - return this.field.getBaseUnit().addTo(temporal, amount); + T result = this.field.getBaseUnit().addTo(temporal, amount); + //adjust daylight saving + if (get(result) != range.getMinimum()) { + result = this.field.adjustInto(result,result.range(this.field).getMinimum()); + } + return result; } /** 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 5abce9e2de3..5de5362fc1d 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 @@ -1336,6 +1336,14 @@ class CronExpressionTests { actual = cronExpression.next(last); assertThat(actual).isNotNull(); assertThat(actual).isEqualTo(expected); + + cronExpression = CronExpression.parse("0 5 0 * * *"); + + last = ZonedDateTime.parse("2021-03-28T01:00:00+01:00[Europe/Amsterdam]"); + expected = ZonedDateTime.parse("2021-03-29T00:05+02:00[Europe/Amsterdam]"); + actual = cronExpression.next(last); + assertThat(actual).isNotNull(); + assertThat(actual).isEqualTo(expected); } @Test From 5ab966fbdefc33840ff2ac4c12b26a6c306b59cf Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Wed, 16 Feb 2022 11:16:27 +0100 Subject: [PATCH 2/2] Polish contribution See gh-28038 --- .../scheduling/support/CronField.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/scheduling/support/CronField.java b/spring-context/src/main/java/org/springframework/scheduling/support/CronField.java index e01e00b6322..adc2c2ffe5d 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/support/CronField.java +++ b/spring-context/src/main/java/org/springframework/scheduling/support/CronField.java @@ -260,7 +260,7 @@ abstract class CronField { * Roll forward the give temporal until it reaches the next higher * order field. Calling this method is equivalent to calling * {@link #elapseUntil(Temporal, int)} with goal set to the - * minimum value of this field's range, except for daylight saving. + * minimum value of this field's range. * @param temporal the temporal to roll forward * @param the type of temporal * @return the rolled forward temporal @@ -269,10 +269,12 @@ abstract class CronField { int current = get(temporal); ValueRange range = temporal.range(this.field); long amount = range.getMaximum() - current + 1; - T result = this.field.getBaseUnit().addTo(temporal, amount); - //adjust daylight saving - if (get(result) != range.getMinimum()) { - result = this.field.adjustInto(result,result.range(this.field).getMinimum()); + T result = this.field.getBaseUnit().addTo(temporal, amount); + current = get(result); + range = result.range(this.field); + // adjust for daylight savings + if (current != range.getMinimum()) { + result = this.field.adjustInto(result, range.getMinimum()); } return result; }