From 5c7d5acecb997f8990f2c6d72d981acd361102ba Mon Sep 17 00:00:00 2001 From: Si Tang Date: Tue, 13 Oct 2020 17:00:28 +0900 Subject: [PATCH] #402 Fix every x years behavior by checking offset in range and correcting previous value calculation in EveryFieldValueGenerator --- .../generator/EveryFieldValueGenerator.java | 10 +++- src/test/java/com/cronutils/Issue402Test.java | 46 ------------------- .../ExecutionTimeQuartzIntegrationTest.java | 44 ++++++++++++++++++ 3 files changed, 52 insertions(+), 48 deletions(-) delete mode 100644 src/test/java/com/cronutils/Issue402Test.java diff --git a/src/main/java/com/cronutils/model/time/generator/EveryFieldValueGenerator.java b/src/main/java/com/cronutils/model/time/generator/EveryFieldValueGenerator.java index 2a93dac7..aed19c73 100644 --- a/src/main/java/com/cronutils/model/time/generator/EveryFieldValueGenerator.java +++ b/src/main/java/com/cronutils/model/time/generator/EveryFieldValueGenerator.java @@ -86,8 +86,14 @@ private int getNext(int reference, Every every) { @Override public int generatePreviousValue(final int reference) throws NoSuchValueException { final Every every = (Every) cronField.getExpression(); + if (reference < from) { + throw new NoSuchValueException(); + } + if (reference > to) { + return to; + } final int period = every.getPeriod().getValue(); - final int remainder = reference % period; + final int remainder = (reference - from) % period; if (remainder == 0) { return reference - period; } else { @@ -100,7 +106,7 @@ protected List generateCandidatesNotIncludingIntervalExtremes(final int final List values = new ArrayList<>(); try { final int offset = offset(); - if (start != offset) { + if (start < offset && offset < end) { values.add(offset); } int reference = generateNextValue(start); diff --git a/src/test/java/com/cronutils/Issue402Test.java b/src/test/java/com/cronutils/Issue402Test.java deleted file mode 100644 index 4b6d3692..00000000 --- a/src/test/java/com/cronutils/Issue402Test.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.cronutils; - -import com.cronutils.model.Cron; -import com.cronutils.model.CronType; -import com.cronutils.model.definition.CronDefinitionBuilder; -import com.cronutils.model.time.ExecutionTime; -import com.cronutils.parser.CronParser; -import org.junit.Ignore; -import org.junit.Test; - -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.Optional; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -@Ignore -public class Issue402Test { - @Test - public void test() { - CronParser parser = new CronParser( CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); - final Cron cron = parser.parse("0 0 0 1 3 ? 2001/2"); -// CronDescriptor cd = CronDescriptor.instance(Locale.US); -// System.out.println(cd.describe(cron)); - - ExecutionTime execution = ExecutionTime.forCron(cron); - - LocalDate date = LocalDate.of(2015, 1, 15); - ZonedDateTime currentDateTime = ZonedDateTime.of(date, LocalTime.MIDNIGHT, ZoneOffset.UTC); - - Optional nextExecution = execution.nextExecution(currentDateTime); - assertTrue(nextExecution.isPresent()); - assertEquals(ZonedDateTime.of(LocalDate.of(2015, 3, 1), LocalTime.MIDNIGHT, ZoneOffset.UTC), nextExecution.get()); - - Optional lastExecution = execution.lastExecution(currentDateTime); - assertTrue(lastExecution.isPresent()); - assertEquals(ZonedDateTime.of(LocalDate.of(2013, 3, 1), LocalTime.MIDNIGHT, ZoneOffset.UTC), lastExecution.get()); - - lastExecution = execution.lastExecution(nextExecution.get()); - assertTrue(lastExecution.isPresent()); - assertEquals(ZonedDateTime.of(LocalDate.of(2013, 3, 1), LocalTime.MIDNIGHT, ZoneOffset.UTC), lastExecution.get()); - } -} diff --git a/src/test/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java b/src/test/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java index bb423956..73acb805 100755 --- a/src/test/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java +++ b/src/test/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java @@ -44,6 +44,7 @@ import static com.cronutils.model.CronType.QUARTZ; import static java.time.ZoneOffset.UTC; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -842,6 +843,49 @@ public void testLastExecutionIssue312() { } } + /** + * Issue #402 + * https://github.com/jmrozanec/cron-utils/issues/402 + * Fix last and next execution time when using every X years + */ + @Test + public void testLastExecutionIssue402() { + // Every 2 years at March 1st midnight + ExecutionTime execution = ExecutionTime.forCron(parser.parse("0 0 0 1 3 ? 2001-2020/2")); + + ZonedDateTime currentDateTime = ZonedDateTime.of(LocalDate.of(2015, 1, 15), LocalTime.MIDNIGHT, ZoneOffset.UTC); + // Check next execution time is correct + Optional nextExecution = execution.nextExecution(currentDateTime); + assertTrue(nextExecution.isPresent()); + assertEquals(ZonedDateTime.of(LocalDate.of(2015, 3, 1), LocalTime.MIDNIGHT, ZoneOffset.UTC), nextExecution.get()); + // Check previous execution time is correct + Optional lastExecution = execution.lastExecution(currentDateTime); + assertTrue(lastExecution.isPresent()); + assertEquals(ZonedDateTime.of(LocalDate.of(2013, 3, 1), LocalTime.MIDNIGHT, ZoneOffset.UTC), lastExecution.get()); + + lastExecution = execution.lastExecution(nextExecution.get()); + assertTrue(lastExecution.isPresent()); + assertEquals(ZonedDateTime.of(LocalDate.of(2013, 3, 1), LocalTime.MIDNIGHT, ZoneOffset.UTC), lastExecution.get()); + + // Assume the current time is before the start time of every expression, check last and next execution.ß + ZonedDateTime timeBeforeStart = ZonedDateTime.of(LocalDate.of(1996, 1, 15), LocalTime.MIDNIGHT, ZoneOffset.UTC); + Optional nextBeforeStart = execution.nextExecution(timeBeforeStart); + assertTrue(nextBeforeStart.isPresent()); + assertEquals(ZonedDateTime.of(LocalDate.of(2001, 3, 1), LocalTime.MIDNIGHT, ZoneOffset.UTC), nextBeforeStart.get()); + + Optional lastBeforeStart = execution.lastExecution(nextBeforeStart.get()); + assertFalse(lastBeforeStart.isPresent()); + + // Assume the current time is before the start time of every expression, check last and next execution.ß + ZonedDateTime timeAfterEnd = ZonedDateTime.of(LocalDate.of(2025, 1, 15), LocalTime.MIDNIGHT, ZoneOffset.UTC); + Optional nextAfterEnd = execution.nextExecution(timeAfterEnd); + assertFalse(nextAfterEnd.isPresent()); + + Optional lastAfterEnd = execution.lastExecution(timeAfterEnd); + assertTrue(lastAfterEnd.isPresent()); + assertEquals(ZonedDateTime.of(LocalDate.of(2019, 3, 1), LocalTime.MIDNIGHT, ZoneOffset.UTC), lastAfterEnd.get()); + } + /** * Issue #424 * https://github.com/jmrozanec/cron-utils/issues/424