TimeUtil { public static ZonedDateTime addOffset(ZonedDateTime time, String offset) { final Matcher matcher = OFFSET_PATTERN.matcher(offset); if (!matcher.matches()) { throw new DateTimeParseException("Unable to parse offset period", offset, 0); } final String sign = matcher.group(1); final String periodOffset = sign + "P" + Optional.ofNullable(matcher.group(2)).orElse("0D"); final String durationOffset = sign + "PT" + Optional.ofNullable(matcher.group(4)).orElse("0S"); final TemporalAmount dateAmount = Period.parse(periodOffset); final TemporalAmount timeAmount = Duration.parse(durationOffset); return time.plus(dateAmount).plus(timeAmount); } 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 shouldSupportZeroOffset() { String offset = "PT0S"; ZonedDateTime time = ZonedDateTime.parse("2017-01-22T08:07:11.22Z"); ZonedDateTime offsetTime = addOffset(time, offset); assertThat(offsetTime, is(time)); }
@Test public void shouldAddOffset() { String offset = "P1M3DT1H7M5S"; ZonedDateTime time = ZonedDateTime.parse("2017-01-22T08:07:11.22Z"); ZonedDateTime offsetTime = addOffset(time, offset); assertThat(offsetTime, is(ZonedDateTime.parse("2017-02-25T09:14:16.22Z"))); }
@Test public void shouldAddOffsetWithNoPeriod() { String offset = "PT1H7M5S"; ZonedDateTime time = ZonedDateTime.parse("2017-01-22T08:07:11.22Z"); ZonedDateTime offsetTime = addOffset(time, offset); assertThat(offsetTime, is(ZonedDateTime.parse("2017-01-22T09:14:16.22Z"))); }
@Test public void shouldAddOffsetWithNoTime() { String offset = "P1M3D"; ZonedDateTime time = ZonedDateTime.parse("2017-01-22T08:07:11.22Z"); ZonedDateTime offsetTime = addOffset(time, offset); assertThat(offsetTime, is(ZonedDateTime.parse("2017-02-25T08:07:11.22Z"))); }
@Test public void shouldAddOffsetWithWeek() { String offset = "P2W"; ZonedDateTime time = ZonedDateTime.parse("2017-01-22T08:07:11.22Z"); ZonedDateTime offsetTime = addOffset(time, offset); assertThat(offsetTime, is(ZonedDateTime.parse("2017-02-05T08:07:11.22Z"))); }
@Test public void shouldAddNegativeOffset() { String offset = "-P1M3DT1H7M5S"; ZonedDateTime time = ZonedDateTime.parse("2017-02-25T09:14:16.22Z"); ZonedDateTime offsetTime = addOffset(time, offset); assertThat(offsetTime, is(ZonedDateTime.parse("2017-01-22T08:07:11.22Z"))); }
@Test public void shouldAddNegativeOffsetWithNoPeriod() { String offset = "-PT1H7M5S"; ZonedDateTime time = ZonedDateTime.parse("2017-01-22T09:14:16.22Z"); ZonedDateTime offsetTime = addOffset(time, offset); assertThat(offsetTime, is(ZonedDateTime.parse("2017-01-22T08:07:11.22Z"))); }