TimeUtil { public static List<Instant> instantsInReversedRange(Instant firstInstant, Instant lastInstant, Schedule schedule) { Preconditions.checkArgument( isAligned(firstInstant, schedule) && isAligned(lastInstant, schedule), "unaligned instant"); Preconditions.checkArgument(!lastInstant.isAfter(firstInstant), "last instant should not be after first instant"); final ExecutionTime executionTime = ExecutionTime.forCron(cron(schedule)); final List<Instant> instants = new ArrayList<>(); Instant currentInstant = firstInstant; while (currentInstant.isAfter(lastInstant)) { instants.add(currentInstant); final ZonedDateTime utcDateTime = currentInstant.atZone(UTC); currentInstant = executionTime.lastExecution(utcDateTime) .orElseThrow(IllegalArgumentException::new) .toInstant(); } return instants; } private  TimeUtil(); static Instant lastInstant(Instant instant, Schedule schedule); static Instant previousInstant(Instant instant, Schedule schedule); static Instant nextInstant(Instant instant, Schedule schedule); static List<Instant> instantsInRange(Instant firstInstant, Instant lastInstant,
                                              Schedule schedule); static List<Instant> instantsInReversedRange(Instant firstInstant, Instant lastInstant,
                                                      Schedule schedule); static boolean isAligned(Instant instant, Schedule schedule); static ZonedDateTime addOffset(ZonedDateTime time, String offset); static ZonedDateTime subtractOffset(ZonedDateTime time, String offset); static Cron cron(Schedule schedule); static Instant offsetInstant(Instant origin, Schedule schedule, int offset);  }
@Test public void shouldGetCorrectInstantsReversed() { final Instant firstTimeHours = parse("2016-01-19T03:00:00.00Z"); final Instant lastTimeHours = parse("2016-01-19T00:00:00.00Z"); final Instant firstTimeDays = parse("2016-01-13T00:00:00.00Z"); final Instant lastTimeDays = parse("2016-01-10T00:00:00.00Z"); final Instant firstTimeWeeks = parse("2016-01-18T00:00:00.00Z"); final Instant lastTimeWeeks = parse("2016-01-11T00:00:00.00Z"); final Instant firstTimeMonths = parse("2013-01-01T00:00:00.00Z"); final Instant lastTimeMonths = parse("2010-01-01T00:00:00.00Z"); assertThat(instantsInReversedRange(firstTimeHours, lastTimeHours, Schedule.HOURS), contains(parse("2016-01-19T03:00:00.00Z"), parse("2016-01-19T02:00:00.00Z"), parse("2016-01-19T01:00:00.00Z"))); assertThat(instantsInReversedRange(firstTimeDays, lastTimeDays, Schedule.DAYS), contains(parse("2016-01-13T00:00:00.00Z"), parse("2016-01-12T00:00:00.00Z"), parse("2016-01-11T00:00:00.00Z"))); assertThat(instantsInReversedRange(firstTimeWeeks, lastTimeWeeks, Schedule.WEEKS), contains(parse("2016-01-18T00:00:00.00Z"))); assertThat(instantsInReversedRange(firstTimeMonths, lastTimeMonths, Schedule.YEARS), contains(parse("2013-01-01T00:00:00.00Z"), parse("2012-01-01T00:00:00.00Z"), parse("2011-01-01T00:00:00.00Z"))); }
@Test public void shouldGetCorrectInstantsForCronReversed() { final Instant firstTimeHours = parse("2016-01-19T03:00:00.00Z"); final Instant lastTimeHours = parse("2016-01-19T00:00:00.00Z"); assertThat(instantsInReversedRange(firstTimeHours, lastTimeHours, Schedule.parse("0 * * * *")), contains(parse("2016-01-19T03:00:00.00Z"), parse("2016-01-19T02:00:00.00Z"), parse("2016-01-19T01:00:00.00Z"))); }
@Test public void shouldGetExceptionIfLastInstantIsBeforeFirstInstantReversed() { final Instant firstTimeHours = parse("2016-01-19T09:00:00.00Z"); final Instant lastTimeHours = parse("2016-01-19T10:00:00.00Z"); expect.expect(IllegalArgumentException.class); expect.expectMessage("last instant should not be after first instant"); instantsInReversedRange(firstTimeHours, lastTimeHours, Schedule.HOURS); }
@Test public void shouldGetExceptionIfLastInstantIsNotAlignedWithScheduleReversed() { final Instant firstTimeHours = parse("2016-01-19T09:00:00.00Z"); final Instant lastTimeHours = parse("2016-01-19T08:10:00.00Z"); expect.expect(IllegalArgumentException.class); expect.expectMessage("unaligned instant"); instantsInReversedRange(firstTimeHours, lastTimeHours, Schedule.HOURS); }
@Test public void shouldGetExceptionIfFirstInstantIsNotAlignedWithScheduleReversed() { final Instant firstTimeHours = parse("2016-01-19T09:10:00.00Z"); final Instant lastTimeHours = parse("2016-01-19T08:00:00.00Z"); expect.expect(IllegalArgumentException.class); expect.expectMessage("unaligned instant"); instantsInReversedRange(firstTimeHours, lastTimeHours, Schedule.HOURS); }