From ab18ab60250e256da4b1502e1786b168c374a229 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Tue, 30 Mar 2021 15:20:11 +0200 Subject: [PATCH] Fix CronExpression issue with ZonedDateTime & DST This commit fixes an issue with CronExpression when used in combination with ZonedDateTime and daylight saving time. Closes gh-26744 --- .../scheduling/support/CronField.java | 9 +++++++-- .../support/CronExpressionTests.java | 19 ++++++++++++++++++- 2 files changed, 25 insertions(+), 3 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 0ed567a24e..d5dee884d6 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -237,7 +237,12 @@ abstract class CronField { public > T elapseUntil(T temporal, int goal) { int current = get(temporal); if (current < goal) { - return this.field.getBaseUnit().addTo(temporal, goal - current); + T result = this.field.getBaseUnit().addTo(temporal, goal - current); + current = get(result); + if (current > goal) { // can occur due to daylight saving, see gh-26744 + result = this.field.getBaseUnit().addTo(result, goal - current); + } + return result; } else { ValueRange range = temporal.range(this.field); 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 28230e51ad..3e359aa449 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1261,6 +1261,23 @@ class CronExpressionTests { assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY); } + @Test + public void daylightSaving() { + CronExpression cronExpression = CronExpression.parse("0 0 9 * * *"); + + ZonedDateTime last = ZonedDateTime.parse("2021-03-27T09:00:00+01:00[Europe/Amsterdam]"); + ZonedDateTime expected = ZonedDateTime.parse("2021-03-28T09:00:00+01:00[Europe/Amsterdam]"); + ZonedDateTime actual = cronExpression.next(last); + assertThat(actual).isNotNull(); + assertThat(actual).isEqualTo(expected); + + last = ZonedDateTime.parse("2021-10-30T09:00:00+01:00[Europe/Amsterdam]"); + expected = ZonedDateTime.parse("2021-10-31T09:00:00+02:00[Europe/Amsterdam]"); + actual = cronExpression.next(last); + assertThat(actual).isNotNull(); + assertThat(actual).isEqualTo(expected); + } + }