Skip to content

Commit 589e08d

Browse files
jwgmeligmeylingvladmihalcea
authored andcommitted
Add support for mapping the Java Period object to a PostgreSQL interval type #128
In PostgreSQL, an interval may comprise years, months, days, hours, minutes and seconds. In Java, an interval is distinguished between a temporal interval (Duration) and a quantity in terms of days, months and years (Period). For example `age(timestamp, timestamp)` returns an interval between two timestamps in days, months and years. The result of this function should as such be mapped to a Java Period instead of an Duration. On the contrary, `timestamp - timestamp` returns an interval between two timestamps in days, hours, minutes and seconds, for which the existing Duration-based type is appropiate.
1 parent 956747d commit 589e08d

File tree

3 files changed

+124
-0
lines changed

3 files changed

+124
-0
lines changed

changelog.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ Version 2.7.0 - IN PROGRESS
33

44
Add support for JSON column values for Oracle #131
55

6+
Add support for mapping the Java Period object to a PostgreSQL interval type #128
7+
68
Add YearMonthTimestampType #127
79

810
Ability to use PostgreSQLEnumType and EnumArrayType with TypedParameterValue #125
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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.Period;
13+
14+
/**
15+
* Maps a Java {@link Duration} object to a PostgreSQL Interval column type.
16+
*
17+
* @author Jan-Willem Gmelig Meyling
18+
* @author Vlad Mihalcea
19+
* @since 2.6.2
20+
*/
21+
public class PostgreSQLPeriodType extends ImmutableType<Period> {
22+
23+
public static final PostgreSQLPeriodType INSTANCE = new PostgreSQLPeriodType();
24+
25+
public PostgreSQLPeriodType() {
26+
super(Period.class);
27+
}
28+
29+
@Override
30+
protected Period get(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException {
31+
final PGInterval interval = (PGInterval) rs.getObject(names[0]);
32+
33+
if (interval == null) {
34+
return null;
35+
}
36+
37+
final int years = interval.getYears();
38+
final int months = interval.getMonths();
39+
final int days = interval.getDays();
40+
41+
return Period.ofYears(years)
42+
.plusMonths(months)
43+
.plusDays(days);
44+
}
45+
46+
@Override
47+
protected void set(PreparedStatement st, Period value, int index, SharedSessionContractImplementor session) throws SQLException {
48+
if (value == null) {
49+
st.setNull(index, Types.OTHER);
50+
} else {
51+
final int days = value.getDays();
52+
final int months = value.getMonths();
53+
final int years = value.getYears();
54+
st.setObject(index, new PGInterval(years, months, days, 0, 0, 0));
55+
}
56+
}
57+
58+
@Override
59+
public int[] sqlTypes() {
60+
return new int[]{Types.OTHER};
61+
}
62+
63+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.vladmihalcea.hibernate.type.interval;
2+
3+
import com.vladmihalcea.hibernate.type.model.BaseEntity;
4+
import com.vladmihalcea.hibernate.type.util.AbstractPostgreSQLIntegrationTest;
5+
import org.hibernate.annotations.TypeDef;
6+
import org.junit.Test;
7+
8+
import javax.persistence.Column;
9+
import javax.persistence.Entity;
10+
import java.time.Period;
11+
12+
import static org.junit.Assert.assertEquals;
13+
14+
/**
15+
* Tests for {@see PostgreSQLIntervalType} Hibernate type.
16+
*
17+
* @author Jan-Willem Gmelig Meyling
18+
*/
19+
public class PostgreSQLPeriodTypeTest extends AbstractPostgreSQLIntegrationTest {
20+
21+
@Override
22+
protected Class<?>[] entities() {
23+
return new Class[]{WorkShift.class};
24+
}
25+
26+
@Test
27+
public void test() {
28+
Period duration = Period.of(1, 2, 3);
29+
30+
doInJPA(entityManager -> {
31+
WorkShift intervalEntity = new WorkShift();
32+
intervalEntity.setId(1L);
33+
intervalEntity.setDuration(duration);
34+
35+
entityManager.persist(intervalEntity);
36+
});
37+
38+
doInJPA(entityManager -> {
39+
WorkShift result = entityManager.find(WorkShift.class, 1L);
40+
assertEquals(duration, result.getDuration());
41+
});
42+
}
43+
44+
@Entity(name = "WorkShift")
45+
@TypeDef(typeClass = PostgreSQLPeriodType.class, defaultForType = Period.class)
46+
public static class WorkShift extends BaseEntity {
47+
48+
@Column(columnDefinition = "interval")
49+
private Period duration;
50+
51+
public Period getDuration() {
52+
return duration;
53+
}
54+
55+
public void setDuration(Period duration) {
56+
this.duration = duration;
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)