An adjuster like next(LocalTime time) only makes sense for types with both a date and a time.
Java's Time API comes with 4 types like that: LocalDateTime, OffsetDateTime, ZonedDateTime, and Instant.
To fully support all 4, the code need special handling for Instant, since Instant and LocalTime are not directly relatable, and for ZonedDateTime, to handle DST overlap.
This implementation can handle all that:
public static TemporalAdjuster next(LocalTime time) {
return temporal -> {
if (temporal instanceof Instant) {
OffsetDateTime utcDateTime = ((Instant) temporal).atOffset(ZoneOffset.UTC);
return next(utcDateTime, time).toInstant();
}
return next(temporal, time);
};
}
@SuppressWarnings("unchecked")
private static <T extends Temporal> T next(T refDateTime, LocalTime targetTime) {
T adjusted = (T) refDateTime.with(targetTime);
if (refDateTime.until(adjusted, ChronoUnit.NANOS) > 0)
return adjusted;
if (adjusted instanceof ChronoZonedDateTime<?>) {
ChronoZonedDateTime<?> laterOffset = ((ChronoZonedDateTime<?>) adjusted).withLaterOffsetAtOverlap();
if (laterOffset != adjusted && refDateTime.until(laterOffset, ChronoUnit.NANOS) > 0)
return (T) laterOffset;
}
return (T) refDateTime.plus(1, ChronoUnit.DAYS).with(targetTime);
}
Test (with now() being 2020-09-18 at some time after 10 AM)
System.out.println(LocalDateTime.now().with(next(LocalTime.of(10, 0))));
System.out.println(OffsetDateTime.now().with(next(LocalTime.of(10, 0))));
System.out.println(ZonedDateTime.now().with(next(LocalTime.of(10, 0))));
System.out.println(Instant.now().with(next(LocalTime.of(10, 0))));
Output
2020-09-19T10:00
2020-09-19T10:00-04:00
2020-09-19T10:00-04:00[America/New_York]
2020-09-19T10:00:00Z
Test Overlap
For US Eastern time zone, DST ends at 2:00 AM on Sunday, November 1, 2020.
// We start at 1:45 AM EDT on November 1, 2020
ZoneId usEastern = ZoneId.of("America/New_York");
ZonedDateTime earlierOffset = ZonedDateTime.of(2020, 11, 1, 1, 45, 0, 0, usEastern);
System.out.println(earlierOffset);
// Now we look for next 1:20 AM after the 1:45 AM, and will find 1:20 AM EST
System.out.println(earlierOffset.with(next(LocalTime.of(1, 20))));
Output
2020-11-01T01:45-04:00[America/New_York]
2020-11-01T01:20-05:00[America/New_York]
Even though the time of day appears earlier (1:20 < 1:45), it is actually a later time.