I want to round off an Instant / LocalDateTime to its closest 5 minutes interval in Java.
Examples: Suppose the time is: 2021-02-08T19:02:49.594 Expected result: 2021-02-08T19:00:00.000
Suppose the time is: 2021-02-08T19:03:49.594 Expected result: 2021-02-08T19:05:00.000
Similarly, if the time is: 2021-02-08T19:56:49.594 Expected result: 2021-02-08T19:55:00.000
Similarly, if the time is: 2021-02-08T19:58:49.594 Expected result: 2021-02-08T20:00:00.000
But if the time is 2021-02-08T19:55:00.000 or 2021-02-08T19:05:00.000 or 2021-02-08T19:00:00.000 then do nothing.
Advertisement
Answer
Here is a general-purpose solution (not just 5 minutes):
public static Instant toNearest(Duration interval, Instant instant) { long intervalMillis = interval.toMillis(); long adjustedInstantMillis = (instant.toEpochMilli() + (intervalMillis / 2)) / intervalMillis * intervalMillis; return Instant.ofEpochMilli(adjustedInstantMillis); } public static LocalDateTime toNearest(Duration interval, LocalDateTime dateTime, ZoneId zoneId) { ZoneRules zoneRules = zoneId.getRules(); Instant instant = toNearest(interval, dateTime.toInstant(zoneRules.getOffset(dateTime))); return LocalDateTime.ofInstant(instant, zoneRules.getOffset(instant)); } public static LocalDateTime toNearest(Duration interval, LocalDateTime dateTime) { return toNearest(interval, dateTime, ZoneId.systemDefault()); } @Test public void toNearestRoundsCorrectly() { assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021, 2, 8, 19, 0, 0))) .isEqualTo(LocalDateTime.of(2021, 2, 8, 19, 0, 0)); assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021, 2, 8, 19, 2, 29, 999999999))) .isEqualTo(LocalDateTime.of(2021, 2, 8, 19, 0, 0)); assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021, 2, 8, 19, 2, 30))) .isEqualTo(LocalDateTime.of(2021, 2, 8, 19, 5, 0)); assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021, 2, 8, 19, 5, 0))) .isEqualTo(LocalDateTime.of(2021, 2, 8, 19, 5, 0)); } @Test public void toNearestTreatsDaylightSavingChangesCorrectly() { assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021,3,27, 23,57,30), ZoneId.of("Europe/London"))) .isEqualTo(LocalDateTime.of(2021,3,28, 0,0,0)); assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021,3,28, 0,57,29,999999999), ZoneId.of("Europe/London"))) .isEqualTo(LocalDateTime.of(2021,3,28, 0,55,0)); assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021,3,28, 0,57,30), ZoneId.of("Europe/London"))) .isEqualTo(LocalDateTime.of(2021,3,28, 2,0,0)); assertThat(toNearest(Duration.ofMinutes(5), LocalDateTime.of(2021,3,28, 2,5,0), ZoneId.of("Europe/London"))) .isEqualTo(LocalDateTime.of(2021,3,28, 2,5,0)); }