package de.ph87.data.series; import lombok.*; import java.time.*; import java.time.temporal.*; import java.util.function.*; public enum Alignment { FIVE(t -> t.truncatedTo(ChronoUnit.MINUTES).minusMinutes(t.getMinute() % 5), Duration.ofMinutes(5), Duration.ofMinutes(5)), HOUR(t -> t.truncatedTo(ChronoUnit.HOURS), Duration.ofHours(1), Duration.ofHours(1)), DAY(t -> t.truncatedTo(ChronoUnit.DAYS), Duration.ofDays(1), Duration.ofDays(1)), WEEK(t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfWeek().getValue() - 1), Period.ofWeeks(1), Duration.ofDays(7)), MONTH(t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfMonth() - 1), Period.ofMonths(1), Duration.ofDays(31)), YEAR(t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfYear() - 1), Period.ofYears(1), Duration.ofDays(366)), ; @NonNull public final Function align; @NonNull public final TemporalAmount amount; @NonNull public final Duration maxDuration; Alignment(@NonNull final Function<@NonNull ZonedDateTime, @NonNull ZonedDateTime> align, @NonNull final TemporalAmount amount, @NonNull final Duration maxDuration) { this.maxDuration = maxDuration; this.align = align; this.amount = amount; } @NonNull public Aligned align(@NonNull final ZonedDateTime date) { return new Aligned(this, date); } @NonNull public ZonedDateTime plus(@NonNull final ZonedDateTime date, final long amount) { return date.plus(multiplyAmount(amount)); } @NonNull @SuppressWarnings("unused") public ZonedDateTime minus(@NonNull final ZonedDateTime date, final long amount) { return plus(date, -amount); } @NonNull public TemporalAmount multiplyAmount(final long amount) { if (this.amount instanceof final Duration duration) { return duration.multipliedBy(amount); } else if (this.amount instanceof final Period period) { return period.multipliedBy((int) amount); } throw new RuntimeException("Cannot multiply unimplemented TemporalAmount: %s".formatted(this.amount)); } }