• Skip to primary navigation
  • Skip to content
  • Skip to primary sidebar

Thoughts on Java

  • Tutorials ▼
    • Hibernate & JPA Tutorials
    • Hibernate Tips
    • Tutorials on YouTube
  • Books & Training ▼
    • Hibernate Tips Book
    • Online Training
    • On-Site Training
  • Consulting ▼
    • Consulting Call
    • Project Coaching
  • About ▼
    • About Thoughts on Java
    • Support Thoughts on Java
    • Resources
  • Member Library
You are here: Home / Hibernate / Hibernate Advanced / How to persist LocalDate and LocalDateTime with JPA
Special thanks to all Thoughts on Java Supporters for supporting this article!

How to persist LocalDate and LocalDateTime with JPA

By Thorben Janssen 17 Comments

  • tweet 
  • share 
  • share 
  • share 
  • share 
  • share 
  • e-mail 


Java 8 brought lots of great features and one of the most important and most anticipated ones was the new Date and Time API. There were lots of issues with the old API and I won’t get into any details on why we needed a new one. I’m sure you had to struggle often enough with it yourself.

All these issues are gone with Java 8. The new Date and Time API is well designed, easy to use and (finally) immutable. The only issue that remains is, that you cannot use it with JPA.

Well, that’s not completely correct. You can use it, but JPA will map it to a BLOB instead of a DATE or TIMESTAMP. That means the database is not aware of the date object and cannot apply any optimization for it. That’s not the way we should or want to do it.

But that doesn’t mean that you can’t use the Date and Time API. You just have to decide how you want to add the support for it. You either use Hibernate 5, which provides proprietary support for the Date and Time API, or you take a few minutes to implement an AttributeConverter like I show you in this post.

 

Don’t want to read? You can watch it here!

Follow me on YouTube to not miss any new videos.

Why does JPA not support LocalDate and LocalDateTime?

The answer is simple, JPA 2.1 was released before Java 8 and the Date and Time API simply didn’t exist at that point in time. Therefore the @Temporal annotation can only be applied to attributes of type java.util.Date and java.util.Calendar.

If you want to store a LocalDate attribute in a DATE column or a LocalDateTime in a TIMESTAMP column, you need to define the mapping to java.sql.Date or java.sql.Timestamp yourself. Thanks to the attribute converter, one of several new features in JPA 2.1, this can be achieved with just a few lines of code.

In the following examples, I will show you how to create an attribute converter for LocalDate and LocalDateTime. If you want to learn more about attribute converter, have a look at How to implement a JPA 2.1 Attribute Converter or one of the other usage examples like a better way to persist enums or encrypting data.

The most important things you need to remember about attribute converter are also described in the free “New Features in JPA 2.1” cheat sheet.

 

The example

Before we create the attribute converters, lets have a look at the example entity for this post.
Attribute converter are part of the JPA 2.1 specification and can therefore be used with any JPA 2.1 implementation, e.g. Hibernate or EclipseLink. I used Wildfly 8.2 with Hibernate 4.3 for the following examples.

Converting LocalDate

As you can see in the following code snippet, there isn’t much you need to do to create an attribute converter for LocalDate.

You need to implement the AttributeConverter<LocalDate, Date> interface with its two methods convertToDatabaseColumn and convertToEntityAttribute. As you can see on the method names, one of them defines the conversion from the type of the entity attribute (LocalDate) to the database column type (Date) and the other one the inverse conversion. The conversion itself is very simple because java.sql.Date already provides the methods to do the conversion to and from a LocalDate.

Additionally the attribute converter needs to be annotated with the @Converter annotation. Due to the optional autoApply=true property, the converter will be applied to all attributes of type LocalDate. Have a look here, if you want to define the usage of the converter for each attribute individually.

The conversion of the attribute is transparent to the developer and the LocalDate attribute can be used as any other entity attribute. You can use it as a query parameter for example.

Converting LocalDateTime

The attribute converter for LocalDateTime is basically the same. You need to implement the AttributeConverter<LocalDateTime, Timestamp> interface and the converter needs to be annotated with the @Converter annotation. Similar to the LocalDateConverter, the conversion between a LocalDateTime and an java.sql.Timestamp is done with the conversion methods of Timestamp. 

 

Conclusion

JPA 2.1 was released before Java 8 and therefore doesn’t support the new Date and Time API. If you want to use the new classes (in the right way), you need to define the conversion to java.sql.Date and java.sql.Timestamp yourself. This can be easily done by implementing the AttributeConverter<EntityType, DatabaseType> interface and annotating the class with @Converter(autoApply=true). By setting autoApply=true, the converter will be applied to all attributes of the EntityType and no changes on the entity are required.

As far as I know, the next JPA release will support the Date and Time API and the different implementations will probably support it even earlier. Hibernate 5 for example will support it as a proprietary feature.

If you want to learn more about the new features in JPA 2.1, have a look at the JPA 2.1 Overview and get your free “New Features in JPA 2.1” cheat sheet.

  • tweet 
  • share 
  • share 
  • share 
  • share 
  • share 
  • e-mail 

Related posts:

  1. Unsynchronized PersistenceContext – How to model conversations with JPA
  2. Ordering vs Sorting with Hibernate – What should you use?
  3. Composition vs. Inheritance with JPA and Hibernate
  4. Ultimate Guide to Implementing equals() and hashCode() with Hibernate
Become a Thoughts on Java Supporter to claim your member perks and to help me write more articles like this.

Filed Under: Hibernate Advanced, JPA, JPA2.1 Tagged With: Date and Time, Mapping

Implement Your Persistence Layer with Ease

Learn More About Hibernate

Need Some Help with Your Project?

Reader Interactions

Comments

  1. Binh Thanh Nguyen says

    August 13, 2015 at 7:14 am

    Thanks, nice tips

    Reply
  2. Caleb Cushing says

    August 14, 2015 at 4:28 am

    or you can upgrade to hibernate 5 and the hibernate-java8 library… support is coming, kind of like winter

    Reply
    • Thorben Janssen says

      September 6, 2015 at 2:36 pm

      Yes, Hibernate 5 provides support for the Date and Time API but there are lots of projects that will not switch to the new Hibernate for quite some time and this post was written before Hibernate 5.0.0.Final was released.

      So, if you cannot use Hibernate 5, writing your own AttributeConverter is a quick and easy way to get support for LocalDate and LocalDateTime.

      Reply
  3. Bernd Müller says

    August 14, 2015 at 1:38 pm

    Works only sometimes, because not null safe.

    Should be:

    public class LocalDateConverter implements AttributeConverter {

    @Override
    public Date convertToDatabaseColumn(LocalDate date) {
    return (date == null ? null : Date.valueOf(date));
    }

    @Override
    public LocalDate convertToEntityAttribute(Date date) {
    return (date == null ? null : date.toLocalDate());

    }
    }

    Regards

    Bernd

    Reply
    • Thorben Janssen says

      September 6, 2015 at 2:28 pm

      Fixed it.

      Thanks!
      Thorben

      Reply
  4. Moody Salem says

    August 21, 2015 at 6:55 pm

    Wondering how Hibernate scans for @Converter annotated classes, because I have these converters in a JAR included into my project and autoApply does not work.

    Reply
    • Thorben Janssen says

      September 6, 2015 at 2:49 pm

      Did you add the converter JAR to your persistence.xml?
      e.g. …
      ../lib/converter.jar
      …

      I didn’t try it out, but if the converter.jar is referenced in the persistence.xml, Hibernate should find the Converter.

      Reply
  5. highdali says

    May 11, 2017 at 9:06 am

    awesome

    Reply
  6. Justyna says

    July 9, 2017 at 1:43 pm

    Thanks a lot! This article is the answer for problem (LocalDate) in my project! I’ll return here yet!

    Reply
    • Thorben Janssen says

      July 10, 2017 at 8:52 am

      You’re welcome 🙂

      Reply
  7. Sathish Kumar says

    November 22, 2017 at 2:46 pm

    Hello Thorben, Awesome writing. Thank you for the post.

    I would like to have some clarification on using LocalDate in a Serializable class. Since its a value based object, Sonar throws me an error saying “Value based objects should not be serialized”. If my requirement is to have a LocalDate field in a JSF managed bean with SessionScoped, then how would I handle it? Kindly requesting your inputs.

    Thank you in advance!

    Reply
    • Thorben Janssen says

      November 23, 2017 at 12:13 pm

      Hi Sathish,

      that’s a complex topic. Here’s an interesting discussion about it: https://groups.google.com/forum/#!topic/sonarqube/WZh_rrh_Avk

      Regards,
      Thorben

      Reply
      • Sathish Kumar says

        November 27, 2017 at 6:33 pm

        Dear Thorben,

        Thank you very much for your reply 🙂

        Regards,
        Sathish

        Reply
  8. Nick G says

    June 19, 2018 at 11:20 pm

    There’s a class: org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters that seems to do exactly this. I actually implemented the converters per this article, but then as I was digging through the dependency code I found this class, commented out everything in the Converter classes and I am still able to defined LocalDate, LocalDateTime fields in my entity classes and they get persisted and read correctly (MariaDB).
    Looks like Spring Data is getting close to implementing JPA 2.1, so it may not matter much longer, but I wanted to comment on an otherwise great article by a great blogger.. keep up the good work T.J.!

    Reply
    • Thorben Janssen says

      July 21, 2018 at 7:11 pm

      Thanks Nick!
      Yes, Spring Data provides similar AttributeConverter for the Date and Time API.
      And if you use JPA 2.2 or Hibernate 5, you don’t even need any AttributeConverter. So, as soon as all projects are updated, we will no longer need this workaround.

      Reply
  9. Grant says

    July 30, 2018 at 5:36 pm

    I am having a problem with this. The date values in my database are being stored 1 day behind.

    I have figured out the cause, but not sure how to fix.
    My application is running in local time (GMT+1), database is MySQL in UTC, and using the useLegacyDatetimeCode=false connection property.

    LocalDate only has concept of year, month and day (not time). The Date.valueOf(locDate) imposes an interpretation of local time zone when creating the Date object, which leads to date in database being wrong when stored (and also when retrieved).

    Any thoughts on how to fix this cleanly? I am only trying to store a date of birth so hoping to be time and timezone agnostic 🙂

    Thanks.

    Reply
    • Thorben Janssen says

      July 31, 2018 at 12:24 pm

      Hi Grant,

      The best way to fix these kinds of issues is to use the same timezone for your application and your database. Using different timezones can cause so many issues, that it’s not worth your time and effort to try to fix all of them.

      Regards,
      Thorben

      Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

Join over 10.000 developers
in the
Thoughts on Java Library

Ebooks Sidebar Get free access to ebooks, cheat sheets and training videos.
Join Now!
Don't like ads?
Become a Thoughts on Java Supporter.
Special Launch Price

Let’s Connect


Thorben Janssen
Independent consultant, trainer and author
  • Facebook
  • GitHub
  • Google+
  • LinkedIn
  • Twitter
  • xing
  • YouTube

Speaking at

7th February 2019
JUG Ostfalen (Germany):
Hibernate Tips 'n' Tricks: Typische Probleme schnell gelöst (Talk - German)

19th March 2019
JavaLand 2019 (Germany):
Hibernate Tips 'n' Tricks: Typische Probleme schnell gelöst (Talk - German)

21st March 2019
JavaLand 2019 (Germany):
Hibernate + jOOQ + Flyway = Die besten Frameworks in einem Stack (1-day Workshop - German)

6th-10th May 2019
JAX 2019 (Germany):
Hibernate Workshop: Komplexe Lösungen jenseits von CRUD (2-day Workshop - German)

6th-10th May 2019
JAX 2019 (Germany):
Spring Data JDBC vs. Spring Data JPA – Wer macht das Rennen? (Talk - German)

6th-10th May 2019
JAX 2019 (Germany):
Microservices mit Hibernate – typische Probleme und Lösungen (Talk - German)

Looking for an on-site training?

Featured Post

14 YouTube Channels You Should Follow in 2019

Getting Started With Hibernate

Entities or DTOs – When should you use which projection?

Ultimate Guide – Association Mappings with JPA and Hibernate

Ultimate Guide to JPQL Queries with JPA and Hibernate

Recent Posts

  • Hibernate Tips: How to Customize a Constructor Expression for Different Subclasses
  • Hibernate Tips: How to Map java.time.Year with JPA and Hibernate
  • Why, When and How to Use DTO Projections with JPA and Hibernate
  • Hibernate Tip: Map a bidirectional one-to-one association with shared composite primary key
  • Implementing the Repository pattern with JPA and Hibernate
  • Hibernate Tips: How to Handle NULL Values while Ordering Query Results in a CriteriaQuery
  • 6 Hibernate Best Practices for Readable and Maintainable Code
  • Can you use Hibernate/EclipseLink/JPA for your microservice?
  • 14 YouTube Channels You Should Follow in 2019
  • Hibernate Tips: How To Map an Entity to a Query
Don't like ads?
Become a Thoughts on Java Supporter.

Copyright © 2019 Thoughts on Java

  • Impressum
  • Disclaimer
  • Privacy Policy