From 1683c050495fad4eb6f82640cc5ff89aeb4e459e Mon Sep 17 00:00:00 2001 From: Jon Parker Date: Wed, 3 Jul 2024 10:46:30 -0400 Subject: [PATCH] docs: Improving docs on Interval.timesBetween --- .../org/mitre/caasd/commons/Interval.java | 17 ++++++- .../java/org/mitre/caasd/commons/Pair.java | 4 ++ .../java/org/mitre/caasd/commons/Triple.java | 4 ++ .../org/mitre/caasd/commons/IntervalTest.java | 46 ++++++++++++++++++- 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/mitre/caasd/commons/Interval.java b/src/main/java/org/mitre/caasd/commons/Interval.java index 3034df3..673e138 100644 --- a/src/main/java/org/mitre/caasd/commons/Interval.java +++ b/src/main/java/org/mitre/caasd/commons/Interval.java @@ -327,8 +327,21 @@ public static Stream datesBetween(Instant start, Instant end) { } /** - * Returns a stream of the epoch floors at the given width between the two dates. I.e. returns - * time bins of size width between start and end. + * Returns a stream of "rounded times" occurring btw the two Instants. + * + * @param start An instant that usually occurs BEFORE the first Instant in the stream. When + * start is a perfect multiple of the width Duration then start will be the first + * value in the output steam (e.g., if the duration width = 5 minutes and start = + * 12:05:00.000 then the start Instant will appear in the output stream) + * @param end An instant that always occurs AFTER the last Instant in the stream. + * + * @return A stream of "Rounded Instants" that come between the start and end. For example, if + * start = 13:52:45 and end = 15:14:45 (82 min apart) timesBetween(start, end, + * Duration.ofMinutes(15)) will return a Stream containing: {14:00:00, 14:15:00, 14:30:00, + * 14:45:00, and 15:00:00} + *

+ * Returns a stream of the epoch floors at the given width between the two dates. I.e. + * returns time bins of size width between start and end. */ public static Stream timesBetween(Instant start, Instant end, Duration width) { if ((end.toEpochMilli() - start.toEpochMilli()) / width.toMillis() > 99999) { diff --git a/src/main/java/org/mitre/caasd/commons/Pair.java b/src/main/java/org/mitre/caasd/commons/Pair.java index d4ffa9d..ed6c452 100644 --- a/src/main/java/org/mitre/caasd/commons/Pair.java +++ b/src/main/java/org/mitre/caasd/commons/Pair.java @@ -33,7 +33,11 @@ * Similarly, it is also a mistake to serialize an {@literal ArrayList} when T is * non-serializable. Despite this vulnerability it is useful for ArrayList, and Pair, to be * Serializable. + *

+ * This class is Deprecated to encourage usage of Java Record classes. This class may or may not be + * removed in the future. */ +@Deprecated public class Pair implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/mitre/caasd/commons/Triple.java b/src/main/java/org/mitre/caasd/commons/Triple.java index f0b7821..9e27fdf 100644 --- a/src/main/java/org/mitre/caasd/commons/Triple.java +++ b/src/main/java/org/mitre/caasd/commons/Triple.java @@ -34,7 +34,11 @@ * Similarly, it is also a mistake to serialize an {@literal ArrayList} when T is * non-serializable. Despite this vulnerability it is useful for ArrayList, and Triple, to be * Serializable. + *

+ * This class is Deprecated to encourage usage of Java Record classes. This class may or may not be + * removed in the future. */ +@Deprecated public class Triple implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/test/java/org/mitre/caasd/commons/IntervalTest.java b/src/test/java/org/mitre/caasd/commons/IntervalTest.java index 16bd526..a8e4ab8 100644 --- a/src/test/java/org/mitre/caasd/commons/IntervalTest.java +++ b/src/test/java/org/mitre/caasd/commons/IntervalTest.java @@ -19,8 +19,10 @@ import static java.time.Instant.EPOCH; import static java.time.temporal.ChronoUnit.DAYS; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.*; +import static org.mitre.caasd.commons.Interval.timesBetween; import java.time.Duration; import java.time.Instant; @@ -113,12 +115,52 @@ public void testIntervalTimesBetween() { .mapToObj(l -> EPOCH.plus(Duration.ofHours(12 * l + 24))) .collect(Collectors.toSet()); - Set itvTimes = Interval.timesBetween(itv.start(), itv.end(), Duration.ofHours(12)) - .collect(Collectors.toSet()); + Set itvTimes = + timesBetween(itv.start(), itv.end(), Duration.ofHours(12)).collect(Collectors.toSet()); assertEquals(Sets.intersection(times, itvTimes).size(), times.size()); } + @Test + public void timeBetween_instantsAreRounded_doNotCoverEntireInterval() { + + Instant start = Instant.parse("2024-07-03T13:52:45.057Z"); + Instant end = Instant.parse("2024-07-03T15:14:45.057Z"); // 82 minutes later.. + + Instant[] times = timesBetween(start, end, Duration.ofMinutes(15)).toArray(Instant[]::new); + + assertThat(times.length, is(5)); + assertThat(times[0], is(Instant.parse("2024-07-03T14:00:00Z"))); + assertThat(times[1], is(Instant.parse("2024-07-03T14:15:00Z"))); + assertThat(times[2], is(Instant.parse("2024-07-03T14:30:00Z"))); + assertThat(times[3], is(Instant.parse("2024-07-03T14:45:00Z"))); + assertThat(times[4], is(Instant.parse("2024-07-03T15:00:00Z"))); + + assertThat(start.isBefore(times[0]), is(true)); + assertThat(end.isAfter(times[4]), is(true)); + + Duration inputDuration = Duration.between(start, end); // 82 min + Duration outputDuration = Time.durationBtw(times); // 60 min + + assertThat(inputDuration.toMillis(), greaterThan(outputDuration.toMillis())); + } + + @Test + public void timeBetween_startAndEnd() { + + Instant start = Instant.parse("2024-07-03T14:00:00Z"); + Instant end = Instant.parse("2024-07-03T15:00:00Z"); // 60 minutes later.. + + Instant[] times = timesBetween(start, end, Duration.ofMinutes(15)).toArray(Instant[]::new); + + assertThat(times.length, is(4)); + + assertThat(times[0], is(Instant.parse("2024-07-03T14:00:00Z"))); + assertThat(times[1], is(Instant.parse("2024-07-03T14:15:00Z"))); + assertThat(times[2], is(Instant.parse("2024-07-03T14:30:00Z"))); + assertThat(times[3], is(Instant.parse("2024-07-03T14:45:00Z"))); + } + @Test public void testComplementOf() { Interval base = new Interval(EPOCH.plusMillis(0L), EPOCH.plusMillis(10L));