TimeUtil { public static Instant lastInstant(Instant instant, Schedule schedule) { final ExecutionTime executionTime = ExecutionTime.forCron(cron(schedule)); final ZonedDateTime utcDateTime = instant.atZone(UTC); return (instant.truncatedTo(ChronoUnit.MINUTES).equals(instant) && executionTime.isMatch(utcDateTime)) ? instant : executionTime.lastExecution(utcDateTime) .orElseThrow(IllegalArgumentException::new) .toInstant(); } 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 shouldGetLastInstant() { final Instant lastTimeHours = parse("2016-01-19T09:00:00.00Z"); final Instant lastTimeDays = parse("2016-01-19T00:00:00.00Z"); final Instant lastTimeWeeks = parse("2016-01-18T00:00:00.00Z"); final Instant lastTimeMonths = parse("2016-01-01T00:00:00.00Z"); final Instant hour = lastInstant(TIME, Schedule.HOURS); assertThat(hour, is(lastTimeHours)); final Instant day = lastInstant(TIME, Schedule.DAYS); assertThat(day, is(lastTimeDays)); final Instant weeks = lastInstant(TIME, Schedule.WEEKS); assertThat(weeks, is(lastTimeWeeks)); final Instant months = lastInstant(TIME, Schedule.MONTHS); assertThat(months, is(lastTimeMonths)); }
@Test public void shouldReturnLastInstantUnchangedIfMatchingTime() { final Instant lastTimeHours = parse("2016-01-19T09:00:00.00Z"); final Instant lastTimeDays = parse("2016-01-19T00:00:00.00Z"); final Instant lastTimeWeeks = parse("2016-01-18T00:00:00.00Z"); final Instant lastTimeMonths = parse("2016-01-01T00:00:00.00Z"); final Instant hour = lastInstant(lastTimeHours, Schedule.HOURS); assertThat(hour, is(lastTimeHours)); final Instant day = lastInstant(lastTimeDays, Schedule.DAYS); assertThat(day, is(lastTimeDays)); final Instant weeks = lastInstant(lastTimeWeeks, Schedule.WEEKS); assertThat(weeks, is(lastTimeWeeks)); final Instant months = lastInstant(lastTimeMonths, Schedule.MONTHS); assertThat(months, is(lastTimeMonths)); }
@Test(expected = IllegalArgumentException.class) public void shouldFailIfNoNextInstance() { lastInstant(parse("2018-01-19T09:00:00.00Z"), Schedule.parse("* * * * * 2017")); }