DateTimeUtils extends TimeUtils { public static long[] parseRepeatableDateTime(String dateTimeStr) { long[] result = new long[3]; if (isRepeatable(Objects.requireNonNull(dateTimeStr, "Date-time string cannot be a null value!"))) { String[] parsed = parseISORepeatable(dateTimeStr); String repeats = parsed[0]; String delayIn = parsed[1]; String periodIn = parsed[2]; Duration startAtDelayDur = null; Duration period = null; if (DateTimeUtils.isPeriod(delayIn)) { OffsetDateTime endTime = OffsetDateTime.parse(periodIn, DateTimeFormatter.ISO_DATE_TIME); period = Duration.of(getMillis(delayIn), ChronoUnit.MILLIS); startAtDelayDur = Duration.between(OffsetDateTime.now(), endTime.minus(period)); } else if (DateTimeUtils.isPeriod(periodIn)) { OffsetDateTime startTime = OffsetDateTime.parse(delayIn, DateTimeFormatter.ISO_DATE_TIME); period = Duration.of(getMillis(periodIn), ChronoUnit.MILLIS); startAtDelayDur = Duration.between(OffsetDateTime.now(), startTime); } else { OffsetDateTime startTime = OffsetDateTime.parse(delayIn, DateTimeFormatter.ISO_DATE_TIME); OffsetDateTime endTime = OffsetDateTime.parse(periodIn, DateTimeFormatter.ISO_DATE_TIME); startAtDelayDur = Duration.between(OffsetDateTime.now(), startTime); period = Duration.between(startTime, endTime); } if (startAtDelayDur.isNegative() || startAtDelayDur.isZero()) { startAtDelayDur = Duration.of(1, ChronoUnit.SECONDS); } result[0] = Long.parseLong(repeats.length() == 0 ? "-1" : repeats); result[1] = startAtDelayDur.toMillis(); result[2] = period.toMillis(); return result; } else { int index = dateTimeStr.indexOf("###"); if (index != -1) { String period = dateTimeStr.substring(index + 3); String delay = dateTimeStr.substring(0, index); result = new long[]{TimeUtils.parseTimeString(delay), TimeUtils.parseTimeString(period)}; return result; } result = new long[]{TimeUtils.parseTimeString(dateTimeStr)}; return result; } }  static boolean isRepeatable(String dateTimeStr); static boolean isPeriod(String dateTimeStr); static boolean isNumeric(String dateTimeStr); static long parseDateTime(String dateTimeStr); static long getMillis(String durationStr); static long parseDuration(String durationStr); static long parseDateAsDuration(String dateTimeStr); static String[] parseISORepeatable(String isoString); static long[] parseRepeatableDateTime(String dateTimeStr);  }
@Test public void testParseRepeatableStartEndDateTime() { OffsetDateTime oneMinuteFromNow = OffsetDateTime.now().plusMinutes(1); OffsetDateTime twoMinutesFromNow = oneMinuteFromNow.plusMinutes(1); String oneMinuteFromNowFormatted = oneMinuteFromNow.format(DateTimeFormatter.ISO_DATE_TIME); String twoMinutesFromNowFormatted = twoMinutesFromNow.format(DateTimeFormatter.ISO_DATE_TIME); String isoString = "R5/" + oneMinuteFromNowFormatted + "/" + twoMinutesFromNowFormatted; long[] parsedRepeatable = DateTimeUtils.parseRepeatableDateTime(isoString); assertEquals(5L, parsedRepeatable[0]); assertTrue("Parsed delay is bigger than " + MINUTE_IN_MILLISECONDS, parsedRepeatable[1] <= MINUTE_IN_MILLISECONDS); assertTrue("Parsed delay is too low! Expected value is between " + MINUTE_IN_MILLISECONDS + " and " + FIFTY_NINE_SECONDS_IN_MILLISECONDS + " but is " + parsedRepeatable[1], parsedRepeatable[1] > FIFTY_NINE_SECONDS_IN_MILLISECONDS); assertEquals("Parsed period should be one minute in milliseconds but is " + parsedRepeatable[2], MINUTE_IN_MILLISECONDS, parsedRepeatable[2]); }
@Test public void testParseRepeatableStartDateTimeAndPeriod() { OffsetDateTime oneMinuteFromNow = OffsetDateTime.now().plusMinutes(1); String oneMinuteFromNowFormatted = oneMinuteFromNow.format(DateTimeFormatter.ISO_DATE_TIME); String isoString = "R5/" + oneMinuteFromNowFormatted + "/PT1M"; long[] parsedRepeatable = DateTimeUtils.parseRepeatableDateTime(isoString); assertEquals(5L, parsedRepeatable[0]); assertTrue("Parsed delay is bigger than " + MINUTE_IN_MILLISECONDS, parsedRepeatable[1] <= MINUTE_IN_MILLISECONDS); assertTrue("Parsed delay is too low! Expected value is between " + MINUTE_IN_MILLISECONDS + " and " + FIFTY_NINE_SECONDS_IN_MILLISECONDS + " but is " + parsedRepeatable[1], parsedRepeatable[1] > FIFTY_NINE_SECONDS_IN_MILLISECONDS); assertEquals("Parsed period should be one minute in milliseconds but is " + parsedRepeatable[2], MINUTE_IN_MILLISECONDS, parsedRepeatable[2]); }
@Test public void testParseRepeatablePeriodAndEndDateTime() { OffsetDateTime twoMinutesFromNow = OffsetDateTime.now().plusMinutes(2); String twoMinutesFromNowFormatted = twoMinutesFromNow.format(DateTimeFormatter.ISO_DATE_TIME); String isoString = "R5/PT1M/" + twoMinutesFromNowFormatted; long[] parsedRepeatable = DateTimeUtils.parseRepeatableDateTime(isoString); assertEquals(5L, parsedRepeatable[0]); assertTrue("Parsed delay is bigger than " + MINUTE_IN_MILLISECONDS, parsedRepeatable[1] <= MINUTE_IN_MILLISECONDS); assertTrue("Parsed delay is too low! Expected value is between " + MINUTE_IN_MILLISECONDS + " and " + FIFTY_NINE_SECONDS_IN_MILLISECONDS + " but is " + parsedRepeatable[1], parsedRepeatable[1] > FIFTY_NINE_SECONDS_IN_MILLISECONDS); assertEquals("Parsed period should be one minute in milliseconds but is " + parsedRepeatable[2], MINUTE_IN_MILLISECONDS, parsedRepeatable[2]); }
@Test public void testParseRepeatablePeriodOnly() { String isoString = "R/PT1M"; long[] parsedRepeatable = DateTimeUtils.parseRepeatableDateTime(isoString); assertEquals(-1L, parsedRepeatable[0]); assertTrue("Parsed delay is bigger than " + MINUTE_IN_MILLISECONDS, parsedRepeatable[1] <= MINUTE_IN_MILLISECONDS); assertTrue("Parsed delay is too low! Expected value is between " + MINUTE_IN_MILLISECONDS + " and " + FIFTY_NINE_SECONDS_IN_MILLISECONDS + " but is " + parsedRepeatable[1], parsedRepeatable[1] > FIFTY_NINE_SECONDS_IN_MILLISECONDS); assertEquals("Parsed period should be one minute in milliseconds but is " + parsedRepeatable[2], MINUTE_IN_MILLISECONDS, parsedRepeatable[2]); }
@Test public void testParseRepeatablePeriodPnYTnMOnly() { OffsetDateTime now = OffsetDateTime.now(); long expectedMillis = Duration.between(now, now.plus(10, ChronoUnit.YEARS).plus(10, ChronoUnit.MINUTES)).toMillis(); String isoString = "R/P10YT10M"; long[] parsedRepeatable = DateTimeUtils.parseRepeatableDateTime(isoString); assertEquals(-1L, parsedRepeatable[0]); assertTrue("Parsed delay is bigger than " + expectedMillis, parsedRepeatable[1] <= expectedMillis); assertTrue( "Parsed delay is too low! Expected value is between " + expectedMillis + " and " + (expectedMillis - 1000) + " but is " + parsedRepeatable[1], parsedRepeatable[1] > expectedMillis - 1000); assertEquals("Parsed period should be 10 years and 10 minutes in milliseconds but is " + parsedRepeatable[2], expectedMillis, parsedRepeatable[2]); }
@Test public void testParseRepeatablePeriodPTnHnMnOnly() { OffsetDateTime now = OffsetDateTime.now(); long expectedMillis = Duration.between(now, now.plus(10, ChronoUnit.HOURS).plus(10, ChronoUnit.MINUTES).plus(10, ChronoUnit.SECONDS)).toMillis(); String isoString = "R/PT10H10M10S"; long[] parsedRepeatable = DateTimeUtils.parseRepeatableDateTime(isoString); assertEquals(-1L, parsedRepeatable[0]); assertTrue("Parsed delay is bigger than " + expectedMillis, parsedRepeatable[1] <= expectedMillis); assertTrue( "Parsed delay is too low! Expected value is between " + expectedMillis + " and " + (expectedMillis - 1000) + " but is " + parsedRepeatable[1], parsedRepeatable[1] > expectedMillis - 1000); assertEquals("Parsed period should be 10 hours, 10 minutes and 10 seconds in milliseconds but is " + parsedRepeatable[2], expectedMillis, parsedRepeatable[2]); }
@Test public void testParseRepeatablePeriodPnYnMnWnDOnly() { OffsetDateTime now = OffsetDateTime.now(); long expectedMillis = Duration .between(now, now.plus(10, ChronoUnit.YEARS).plus(10, ChronoUnit.MONTHS).plus(10, ChronoUnit.WEEKS).plus(10, ChronoUnit.DAYS)).toMillis(); String isoString = "R/P10Y10M10W10D"; long[] parsedRepeatable = DateTimeUtils.parseRepeatableDateTime(isoString); assertEquals(-1L, parsedRepeatable[0]); assertTrue("Parsed delay is bigger than " + expectedMillis, parsedRepeatable[1] <= expectedMillis); assertTrue( "Parsed delay is too low! Expected value is between " + expectedMillis + " and " + (expectedMillis - 1000) + " but is " + parsedRepeatable[1], parsedRepeatable[1] > expectedMillis - 1000); assertEquals("Parsed period should be 10 years, 10 months, 10 weeks and 10 days in milliseconds but is " + parsedRepeatable[2], expectedMillis, parsedRepeatable[2]); }
@Test public void testParseRepeatablePeriodPnYnMnWnDTnHnMnOnly() { OffsetDateTime now = OffsetDateTime.now(); long expectedMillis = Duration.between(now, now.plus(10, ChronoUnit.YEARS).plus(10, ChronoUnit.MONTHS).plus(10, ChronoUnit.WEEKS) .plus(10, ChronoUnit.DAYS).plus(10, ChronoUnit.HOURS).plus(10, ChronoUnit.MINUTES).plus(10, ChronoUnit.SECONDS)).toMillis(); String isoString = "R/P10Y10M10W10DT10H10M10S"; long[] parsedRepeatable = DateTimeUtils.parseRepeatableDateTime(isoString); assertEquals(-1L, parsedRepeatable[0]); assertTrue("Parsed delay is bigger than " + expectedMillis, parsedRepeatable[1] <= expectedMillis); assertTrue( "Parsed delay is too low! Expected value is between " + expectedMillis + " and " + (expectedMillis - 1000) + " but is " + parsedRepeatable[1], parsedRepeatable[1] > expectedMillis - 1000); assertEquals("Parsed period should be 10 years, 10 months, 10 weeks, 10 days, 10 hours, 10 minutes and 10 seconds in milliseconds but is " + parsedRepeatable[2], expectedMillis, parsedRepeatable[2]); }