1 package com.vladmihalcea.hibernate.type.interval;
2
3 import com.vladmihalcea.hibernate.type.ImmutableType;
4 import org.hibernate.engine.spi.SharedSessionContractImplementor;
5 import org.postgresql.util.PGInterval;
6
7 import java.sql.PreparedStatement;
8 import java.sql.ResultSet;
9 import java.sql.SQLException;
10 import java.sql.Types;
11 import java.time.Duration;
12 import java.time.temporal.ChronoUnit;
13
14 /**
15  * Maps a Java {@link Duration} object to a PostgreSQL Interval column type.
16  * <p>
17  * For more details about how to use it, check out <a href="https://vladmihalcea.com/map-postgresql-interval-java-duration-hibernate/">this article</a> on <a href="https://vladmihalcea.com/">vladmihalcea.com</a>.
18  *
19  * @author Jan-Willem Gmelig Meyling
20  * @author Vlad Mihalcea
21  * @since 2.5.1
22  */

23 public class PostgreSQLIntervalType extends ImmutableType<Duration> {
24
25     private static final double MICROS_IN_SECOND = 1000000;
26
27     public static final PostgreSQLIntervalType INSTANCE = new PostgreSQLIntervalType();
28
29     public PostgreSQLIntervalType() {
30         super(Duration.class);
31     }
32
33     @Override
34     protected Duration get(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException {
35         final PGInterval interval = (PGInterval) rs.getObject(names[0]);
36
37         if (interval == null) {
38             return null;
39         }
40
41         final int days = interval.getDays();
42         final int hours = interval.getHours();
43         final int minutes = interval.getMinutes();
44         final int seconds = (int) interval.getSeconds();
45         final int micros = (int) Math.round((interval.getSeconds() - seconds) * MICROS_IN_SECOND);
46
47         return Duration.ofDays(days)
48                 .plus(hours, ChronoUnit.HOURS)
49                 .plus(minutes, ChronoUnit.MINUTES)
50                 .plus(seconds, ChronoUnit.SECONDS)
51                 .plus(micros, ChronoUnit.MICROS);
52     }
53
54     @Override
55     protected void set(PreparedStatement st, Duration value, int index, SharedSessionContractImplementor session) throws SQLException {
56         if (value == null) {
57             st.setNull(index, Types.OTHER);
58         } else {
59             final int days = (int) value.toDays();
60             final int hours = (int) (value.toHours() % 24);
61             final int minutes = (int) (value.toMinutes() % 60);
62             final int seconds = (int) (value.getSeconds() % 60);
63             final int micros = value.getNano() / 1000;
64             final double secondsWithFraction = seconds + (micros / MICROS_IN_SECOND);
65             st.setObject(index, new PGInterval(0, 0, days, hours, minutes, secondsWithFraction));
66         }
67     }
68
69     @Override
70     public int[] sqlTypes() {
71         return new int[]{Types.OTHER};
72     }
73
74 }
75