Red Hat
Feb 19, 2018
by Vlad Mihalcea

Hibernate ORM 5.3 implements the JPA 2.2 standard. Over the following weeks, we are going to present various features introduced by JPA 2.2.

The JPA 2.2 specification says that the following Java 8 types are now supported:

  • java.time.LocalDate,

  • java.time.LocalTime,

  • java.time.LocalDateTime,

  • java.time.OffsetTime,

  • java.time.OffsetDateTime

In this article, you are going to see that Hibernate ORM supports all these types, and even more:

  • java.time.Duration,

  • java.time.ZonedDateTime

Entity mapping

Assuming you have the following entity:

@Entity(name = "DateTimeEntity")
      public static class DateTimeEntity {
      
              @Id
              private Integer id;
      
              @Column(name = "duration_value")
              private Duration duration = Duration.of( 20, ChronoUnit.DAYS );
      
              @Column(name = "instant_value")
              private Instant instant = Instant.now();
      
              @Column(name = "local_date")
              private LocalDate localDate = LocalDate.now();
      
              @Column(name = "local_date_time")
              private LocalDateTime localDateTime = LocalDateTime.now();
      
              @Column(name = "local_time")
              private LocalTime localTime = LocalTime.now();
      
              @Column(name = "offset_date_time")
              private OffsetDateTime offsetDateTime = OffsetDateTime.now();
      
              @Column(name = "offset_time")
              private OffsetTime offsetTime = OffsetTime.now();
      
              @Column(name = "zoned_date_time")
              private ZonedDateTime zonedDateTime = ZonedDateTime.now();
      
              //Getters and setters omitted for brevity
      }

The DateTimeEntity will have an associated database table that looks as follows:

create table DateTimeEntity
      (
          id                  integer not null,
          duration_value      bigint,
          instant_value       timestamp,
          local_date          date,
          local_date_time     timestamp,
          local_time          time,
          offset_date_time    timestamp,
          offset_time         time,
          zoned_date_time     timestamp,
          primary key (id)
      )

Testing time

When persisting one DateTimeEntity:

final DateTimeEntity dateTimeEntity = new DateTimeEntity();
      dateTimeEntity.setId( 1 );
      
      doInHibernate(this::sessionFactory, session -> {
          session.persist( dateTimeEntity );
      } );

Hibernate ORM generates the following SQL statement:

insert into DateTimeEntity
      (
              duration_value,
              instant_value,
              local_date,
              local_date_time,
              local_time,
              offset_date_time,
              offset_time,
              zoned_date_time,
              id
      )
      values
              (?, ?, ?, ?, ?, ?, ?, ?, ?)
      
      -- binding parameter [1] as [BIGINT]         - [PT480H]
      -- binding parameter [2] as [TIMESTAMP] - [2018-02-20T13:52:31.333Z]
      -- binding parameter [3] as [DATE]                 - [2018-02-20]
      -- binding parameter [4] as [TIMESTAMP] - [2018-02-20T15:52:31.329]
      -- binding parameter [5] as [TIME]                 - [15:52:31.333]
      -- binding parameter [6] as [TIMESTAMP] - [2018-02-20T15:52:31.333+02:00]
      -- binding parameter [7] as [TIME]                 - [15:52:31.333+02:00]
      -- binding parameter [8] as [TIMESTAMP] - [2018-02-20T15:52:31.333+02:00[Europe/Athens]]
      -- binding parameter [9] as [INTEGER]         - [1]

When fetching the entity:

DateTimeEntity _dateTimeEntity = session.find( DateTimeEntity.class, 1 );

Hibernate ORM generates the following SQL statement:

select
              dt.id as id1_0_0_,
              dt.duration_value as duration2_0_0_,
              dt.instant_value as instant_3_0_0_,
              dt.local_date as local_da4_0_0_,
              dt.local_date_time as local_da5_0_0_,
              dt.local_time as local_ti6_0_0_,
              dt.offset_date_time as offset_d7_0_0_,
              dt.offset_time as offset_t8_0_0_,
              dt.zoned_date_time as zoned_da9_0_0_
      from
              DateTimeEntity dt
      where
              dt.id = ?
      
      -- binding parameter [1] as [INTEGER] - [1]
      
      -- extracted value ([duration2_0_0_] : [BIGINT])         - [PT480H]
      -- extracted value ([instant_3_0_0_] : [TIMESTAMP]) - [2018-02-20T13:52:31.333Z]
      -- extracted value ([local_da4_0_0_] : [DATE])                 - [2018-02-20]
      -- extracted value ([local_da5_0_0_] : [TIMESTAMP]) - [2018-02-20T15:52:31.329]
      -- extracted value ([local_ti6_0_0_] : [TIME])                 - [15:52:31]
      -- extracted value ([offset_d7_0_0_] : [TIMESTAMP]) - [2018-02-20T15:52:31.333+02:00]
      -- extracted value ([offset_t8_0_0_] : [TIME])                 - [15:52:31+02:00]
      -- extracted value ([zoned_da9_0_0_] : [TIMESTAMP]) - [2018-02-20T15:52:31.333+02:00[Europe/Athens]]
      
      -- duration (Duration)                                 -> 1728000000000000
      -- instant (Instant)                                 -> 2018-02-20T13:52:31.333Z
      -- localDate (LocalDate)                         -> 2018-02-20
      -- localDateTime (LocalDateTime)         -> 2018-02-20 15:52:31.3
      -- localTime (LocalTime)                         -> 15:52:31
      -- offsetDateTime (OffsetDateTime)         -> 2018-02-20 15:52:31.3 +02:00
      -- offsetTime (OffsetTime)                         -> 15:52:31.0 +02:00
      -- zonedDateTime (ZonedDateTime)         -> 2018-02-20 15:52:31.3 Europe/Athens

Conclusion

Since version 5.0, Hibernate ORM has been supporting the Java 8 new types via the hibernate-java8 module.

In version 5.2, these types were integrated into hibernate-core and Hibernate ORM 5.3 is now supporting JPA 2.2, supporting the Java 8 Date/Time attributes specified by the JPA standard and even more than that.

Original Post