How to store date/time and timestamps in UTC time zone with JPA and Hibernate

Viewed 195162

How can I configure JPA/Hibernate to store a date/time in the database as UTC (GMT) time zone? Consider this annotated JPA entity:

public class Event {
    @Id
    public int id;

    @Temporal(TemporalType.TIMESTAMP)
    public java.util.Date date;
}

If the date is 2008-Feb-03 9:30am Pacific Standard Time (PST), then I want the UTC time of 2008-Feb-03 5:30pm stored in the database. Likewise, when the date is retrieved from the database, I want it interpreted as UTC. So in this case 530pm is 530pm UTC. When it's displayed it will be formatted as 9:30am PST.

11 Answers

To the best of my knowledge, you need to put your entire Java app in UTC timezone (so that Hibernate will store dates in UTC), and you'll need to convert to whatever timezone desired when you display stuff (at least we do it this way).

At startup, we do:

TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));

And set the desired timezone to the DateFormat:

fmt.setTimeZone(TimeZone.getTimeZone("Europe/Budapest"))

With Spring Boot JPA, use the below code in your application.properties file and obviously you can modify timezone to your choice

spring.jpa.properties.hibernate.jdbc.time_zone = UTC

Then in your Entity class file,

@Column
private LocalDateTime created;

You would think this common problem would be taken care of by Hibernate. But its not! There are a few "hacks" to get it right.

The one I use is to store the Date as a Long in the database. So I am always working with milliseconds after 1/1/70. I then have getters and setters on my Class that return/accept only Dates. So the API remains the same. The down side is that I have longs in the database. SO with SQL I can pretty much only do <,>,= comparisons -- not fancy date operators.

Another approach is to user a custom mapping type as described here: http://www.hibernate.org/100.html

I think the correct way to deal with this is to use a Calendar instead of a Date though. With the Calendar you can set the TimeZone before persisting.

NOTE: Silly stackoverflow won't let me comment, so here is a response to david a.

If you create this object in Chicago:

new Date(0);

Hibernate persists it as "12/31/1969 18:00:00". Dates should be devoid of timezone, so I'm not sure why the adjustment would be made.

There are several timezones in operation here:

  1. Java's Date classes (util and sql), which have implicit timezones of UTC
  2. The timezone your JVM is running in, and
  3. the default timezone of your database server.

All of these can be different. Hibernate/JPA has a severe design deficiency in that a user cannot easily ensure that timezone information is preserved in the database server (which allows reconstruction of correct times and dates in the JVM).

Without the ability to (easily) store timezone using JPA/Hibernate then information is lost and once information is lost it becomes expensive to construct it (if at all possible).

I would argue that it is better to always store timezone information (should be the default) and users should then have the optional ability to optimize the timezone away (although it only really affects display, there is still an implicit timezone in any date).

Sorry, this post doesn't provide a work-around (that's been answered elsewhere) but it is a rationalization of why always storing timezone information around is important. Unfortunately it seems many Computer Scientists and programming practitioners argue against the need for timezones simply because they don't appreciate the "loss of information" perspective and how that makes things like internationalization very difficult - which is very important these days with web sites accessible by clients and people in your organization as they move around the world.

Date is not in any time zone (it is a millisecond office from a defined moment in time same for everyone), but underlying (R)DBs generally store timestamps in political format (year, month, day, hour, minute, second, ...) that is time-zone sensitive.

To be serious, Hibernate MUST be allow being told within some form of mapping that the DB date is in such-and-such timezone so that when it loads or stores it it does not assume its own...

Related