JPA Buddy
announcement - icon

JPA is huge! It covers nearly every aspect of communication between relational databases and the Java application and is deeply integrated into all major frameworks.

If you're using IntelliJ, JPA Buddy is super helpful. The plugin gently guides you through the subtleties of the most popular JPA implementations, visually reminds you of JPA features, generates code that follows best practices, and integrates intelligent inspections to improve your existing persistence code.

More concretely, it provides powerful tooling to generate Spring Data JPA repositories and methods, Flyway Versioned Migrations, Liquibase Differential Changelogs, DDL and SQL statements, DTO objects, and MapStruct interfaces.

Oh, and it actually generates JPA entities from an existing database and gradually update the data model as the database evolves! Yeah.

>> Become a lot more productive with JPA Buddy

Persistence top

Get started with Spring Data JPA through the reference Learn Spring Data JPA course:


1. Overview

In this tutorial, we'll show how to map temporal column values in Hibernate, including the classes from java.sql, java.util and java.time packages.

2. Project Setup

To demonstrate the mapping of the temporal types, we're going to need the H2 database and the latest version of the hibernate-core library:


For the current version of the hibernate-core library, head over to the Maven Central repository.

3. Time Zone Setup

When dealing with dates, it's a good idea to set a specific time zone for the JDBC driver. This way, our application will be independent of the current time zone of the system.

For our example, we'll set it up on a per-session basis:

session = HibernateUtil.getSessionFactory().withOptions()

Another way would be to set up the hibernate.jdbc.time_zone property in the Hibernate properties file that is used to construct the session factory. This way, we could specify the time zone once for the entire application.

4. Mapping java.sql Types

The java.sql package contains JDBC types that are aligned with the types defined by the SQL standard:

  • Date corresponds to the DATE SQL type, which is only a date without time.
  • Time corresponds to the TIME SQL type, which is a time of the day specified in hours, minutes and seconds.
  • Timestamp includes information about date and time with precision up to nanoseconds and corresponds to the TIMESTAMP SQL type.

These types are in line with SQL, so their mapping is relatively straightforward.

We can use either the @Basic or the @Column annotation:

public class TemporalValues {

    private java.sql.Date sqlDate;

    private java.sql.Time sqlTime;

    private java.sql.Timestamp sqlTimestamp;


We could then set the corresponding values:

  java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));

Note that choosing java.sql types for entity fields may not always be a good choice. These classes are JDBC-specific and contain a lot of deprecated functionality.

5. Mapping java.util.Date Type

The type java.util.Date contains both date and time information, up to millisecond precision. But it doesn't directly relate to any SQL type.

This is why we need another annotation to specify the desired SQL type:

private java.util.Date utilDate;

private java.util.Date utilTime;

private java.util.Date utilTimestamp;

The @Temporal annotation has the single parameter value of type TemporalType. It can be either DATE, TIME or TIMESTAMP, depending on the underlying SQL type that we want to use for the mapping.

We could then set the corresponding fields:

  new SimpleDateFormat("yyyy-MM-dd").parse("2017-11-15"));
  new SimpleDateFormat("HH:mm:ss").parse("15:30:14"));
  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
    .parse("2017-11-15 15:30:14.332"));

As we've seen, the java.util.Date type (milliseconds precision) is not precise enough to handle the Timestamp value (nanoseconds precision).

So, when we retrieve the entity from the database, we'll unsurprisingly find a java.sql.Timestamp instance in this field, even if we initially persisted a java.util.Date:

temporalValues = session.get(TemporalValues.class, 
  .isEqualTo(java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));

This should be fine for our code since Timestamp extends Date.

6. Mapping java.util.Calendar Type

As with the java.util.Date, the java.util.Calendar type may be mapped to different SQL types, so we have to specify them with @Temporal.

The only difference is that Hibernate does not support mapping Calendar to TIME:

private java.util.Calendar calendarDate;

private java.util.Calendar calendarTimestamp;

Here's how we can set the value of the field:

Calendar calendarDate = Calendar.getInstance(
calendarDate.set(Calendar.YEAR, 2017);
calendarDate.set(Calendar.MONTH, 10);
calendarDate.set(Calendar.DAY_OF_MONTH, 15);

7. Mapping java.time Types

Since Java 8, the new Java Date and Time API is available for dealing with temporal values. This API fixes many of the problems of java.util.Date and java.util.Calendar classes.

The types from the java.time package are directly mapped to corresponding SQL types.

So, there's no need to explicitly specify @Temporal annotation:

  • LocalDate is mapped to DATE.
  • LocalTime and OffsetTime are mapped to TIME.
  • Instant, LocalDateTime, OffsetDateTime and ZonedDateTime are mapped to TIMESTAMP.

This means that we can mark these fields only with @Basic (or @Column) annotation:

private java.time.LocalDate localDate;

private java.time.LocalTime localTime;

private java.time.OffsetTime offsetTime;

private java.time.Instant instant;

private java.time.LocalDateTime localDateTime;

private java.time.OffsetDateTime offsetDateTime;

private java.time.ZonedDateTime zonedDateTime;

Every temporal class in the java.time package has a static parse() method to parse the provided String value using the appropriate format.

So, here's how we can set the values of the entity fields:




8. Conclusion

In this article, we’ve shown how to map temporal values of different types in Hibernate.

The source code for the article is available over on GitHub.

Persistence bottom
Get started with Spring Data JPA through the reference Learn Spring Data JPA course: >> CHECK OUT THE COURSE
Persistence footer banner
Comments are closed on this article!