package com.github.marschall.threeten.jpa.h2; import static java.time.temporal.ChronoUnit.DAYS; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import org.h2.api.TimestampWithTimeZone; import org.h2.util.DateTimeUtils; final class TimestampWithTimeZoneConverter { private TimestampWithTimeZoneConverter() { throw new AssertionError("not instantiable"); } static TimestampWithTimeZone offsetDateTimeToTimestampWithTimeZone(OffsetDateTime attribute) { if (attribute == null) { return null; } LocalDateTime localDateTime = attribute.toLocalDateTime(); LocalDate localDate = localDateTime.toLocalDate(); ZoneOffset zoneOffset = attribute.getOffset(); int year = localDate.getYear(); int month = localDate.getMonthValue(); int day = localDate.getDayOfMonth(); long dateValue = DateTimeUtils.dateValue(year, month, day); LocalDateTime midnight = localDateTime.truncatedTo(DAYS); Duration duration = Duration.between(midnight, localDateTime); long timeNanos = duration.toNanos(); int totalSeconds = zoneOffset.getTotalSeconds(); short timeZoneOffsetMins = toShortExact(SECONDS.toMinutes(totalSeconds)); return new TimestampWithTimeZone(dateValue, timeNanos, timeZoneOffsetMins); } static OffsetDateTime timestampWithTimeZoneToOffsetDateTime(TimestampWithTimeZone dbData) { if (dbData == null) { return null; } long dateValue = dbData.getYMD(); int year = DateTimeUtils.yearFromDateValue(dateValue); int month = DateTimeUtils.monthFromDateValue(dateValue); int day = DateTimeUtils.dayFromDateValue(dateValue); LocalDate localDate = LocalDate.of(year, month, day); long timeNanos = dbData.getNanosSinceMidnight(); LocalDateTime localDateTime = localDate.atStartOfDay().plusNanos(timeNanos); short timeZoneOffsetMins = dbData.getTimeZoneOffsetMins(); int offsetSeconds = Math.toIntExact(MINUTES.toSeconds(timeZoneOffsetMins)); ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSeconds); return OffsetDateTime.of(localDateTime, offset); } private static short toShortExact(long l) { if (l > Short.MAX_VALUE) { throw new AssertionError(); } if (l < Short.MIN_VALUE) { throw new AssertionError(); } return (short) l; } }