Date and Time Mappings With Hibernate and JPA
Date and Time Mappings With Hibernate and JPA
www.thoughts-on-java.org
Date and Time Mappings with Hibernate and JPA
TemporalType.TIMESTAMP to map it to a SQL TIMESTAMP
column
I’m using the @Temporal annotation in the following code snippet to
map an attribute of type java.util.Date to a TIMESTAMP column and
an attribute of type java.util.Calendar to a DATE column.
@Entity
public class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Temporal(TemporalType.TIMESTAMP)
private Date utilDate;
@Temporal(TemporalType.DATE)
private Calendar utilCalendar;
...
}
You can then use these attributes in the same way you use any other
entity attributes.
www.thoughts-on-java.org
Date and Time Mappings with Hibernate and JPA
If you activate the logging of SQL statements, you can find the
following messages in your log file.
www.thoughts-on-java.org
Date and Time Mappings with Hibernate and JPA
That’s because the classes in the java.sql package match the SQL data
types.
That enables your persistence provider, e.g., Hibernate, to identify
the mapping automatically. So, without providing any additional
annotations:
java.sql.Date gets mapped to SQL DATE,
java.sql.TIME gets mapped to SQL TIME and
java.sql.TIMESTAMP gets mapped to SQL TIMESTAMP.
@Entity
public class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
...
}
You can then use these attributes in your business code to store date
and time information in your database.
MyEntity e = new MyEntity();
e.setSqlDate(new java.sql.Date(119, 6, 18));
e.setSqlTime(new Time(15, 05, 30));
e.setSqlTimestamp(new Timestamp(119, 6, 18, 15, 05, 30, 0));
em.persist(e);
www.thoughts-on-java.org
Date and Time Mappings with Hibernate and JPA
And after you activated the logging of SQL statements, you can see
that Hibernate maps the entity attributes to the corresponding SQL
types.
java.time.LocalDateT X X TIMESTAMP
ime
java.time.OffsetTime X X TIME_WITH_TIMEZ
ONE
java.time.OffsetDate X X TIMESTAMP_WITH_
Time TIMEZONE
java.time.Duration - X BIGINT
java.time.Instant - X TIMESTAMP
java.time.ZonedDate - X TIMESTAMP
Time
www.thoughts-on-java.org
Date and Time Mappings with Hibernate and JPA
As you can see in the table, Hibernate supports a few more Date and
Time classes than JPA. You can easily add support for additional
classes by implementing an AttributeConverter. I used it in a previous
article to map an attribute of type Duration with JPA.
Hibernate’s proprietary support for Duration and Instant works fine.
But you should be careful if you want to use Hibernate’s mapping of
ZonedDateTime. The handling of timezones and the mapping to a
TIMESTAMP column presents a few pitfalls. I get into more details
about that in the Working with ZonedDateTime section.
Let’s first take a look at a basic entity mapping.
@Entity
public class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
www.thoughts-on-java.org
Date and Time Mappings with Hibernate and JPA
MyEntity e = new MyEntity();
e.setLocalDate(LocalDate.of(2019, 7, 19));
e.setLocalDateTime(LocalDateTime.of(2019, 7, 19, 15, 05, 30));
e.setOffsetTime(OffsetTime.of(15, 05, 30, 0, ZoneOffset.ofHours(+2)));
e.setOffsetDateTime(OffsetDateTime.of(2019, 7, 19, 15, 05, 30, 0,
ZoneOffset.ofHours(+2)));
em.persist(e);
The classes of the Date and Time API clearly define if they store date
and/or time information. So, the JPA specification and all
implementing frameworks can map them to the correct SQL types.
11:52:26,305 DEBUG SQL:94 - insert into MyEntity (duration, instant, localDate,
localDateTime, offsetDateTime, offsetTime, sqlDate, sqlTime, sqlTimestamp,
utilCalendar, utilDate, zonedDateTime, id) values (?, ?, ?, ?, ?, ?, ?, ?)
11:52:26,306 TRACE BasicBinder:65 - binding parameter [1] as [BIGINT] - [PT2H]
11:52:26,307 TRACE BasicBinder:65 - binding parameter [2] as [TIMESTAMP] -
[2019-07-22T09:52:26.284946300Z]
11:52:26,308 TRACE BasicBinder:65 - binding parameter [3] as [DATE] - [2019-
07-19]
11:52:26,308 TRACE BasicBinder:65 - binding parameter [4] as [TIMESTAMP] -
[2019-07-19T15:05:30]
11:52:26,312 TRACE BasicBinder:65 - binding parameter [5] as [TIMESTAMP] -
[2019-07-19T15:05:30+02:00]
11:52:26,313 TRACE BasicBinder:65 - binding parameter [6] as [TIME] -
[15:05:30+02:00]
11:52:26,324 TRACE BasicBinder:65 - binding parameter [7] as [TIMESTAMP] -
[2019-07-18T15:05:30-04:00[UTC-04:00]]
11:52:26,324 TRACE BasicBinder:65 - binding parameter [8] as [BIGINT] - [1]
www.thoughts-on-java.org
Date and Time Mappings with Hibernate and JPA
Working with ZonedDateTime
As I mentioned early, using Hibernate’s support for ZonedDateTime
is risky. And let’s be honest, I don’t recommend using it.
Hibernate maps a ZonedDateTime to an SQL TIMESTAMP without
time zone information. It converts the ZonedDateTime into the local
time zone of the JVM and then stores it in the database. And when it
reads the TIMESTAMP, it adds the local time zone information to it.
But you can see in the database, that it converted the time zone from
UTC-4 to UTC+2, which is my local time zone.
www.thoughts-on-java.org
Date and Time Mappings with Hibernate and JPA
will then use the configured time zone instead of the one used by
your local JVM. I recommend using the UTC time zone.
<persistence>
<persistence-unit name="my-persistence-unit">
...
<properties>
<property name="hibernate.dialect"
value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.jdbc.time_zone" value="UTC"/>
...
</properties>
</persistence-unit>
</persistence>
When you now rerun the test, you will not see any difference in the
log file.
But if you look at the database table, you can see, that Hibernate now
converted the ZonedDateTime to the UTC time zone.
www.thoughts-on-java.org
Date and Time Mappings with Hibernate and JPA
Conclusion
JPA and Hibernate can map database columns of type DATE, TIME
and TIMESTAMP to various Java classes. You can map them to:
www.thoughts-on-java.org