I am using hibernate + spring and want to store/load timestamps in UTC. I've read that I should add a property, so I added this to my application.properties
spring.jpa.properties[hibernate.jdbc.time_zone]=UTC
This worked for one part of the problem - now dates are saved in utc in the database. But when I retrieve timestamps, they are transformed into default timezone. How can I fix this without setting default time zone to UTC?
The property of the entity has type LocalDateTime.
I ran the code, and noticed that the proper result set method is used during get(the one that accepts calendar) with instance that has zone info storing UTC. But after setting calendar's values to the one retrieved from the database, the calendar is transformed into Timestamp with this code
Timestamp ts = new Timestamp(c.getTimeInMillis());
In debug mode, I see that ts stores cdate field with value of timestamp in default time zone(not UTC).
First of all, if we are talking about Hibernate 5 (5.2.3 - 5.6.x if to be precise) the purpose of
hibernate.jdbc.time_zonesetting is not to give the ability for application developer to implement some kind of sophisticated date/time logic, but to synchronize persistence provider with underlying database, that is clearly stated in the corresponding CR:basically: you definitely need to set up
hibernate.jdbc.time_zoneif (mine: and only if) SQL statement likeSELECT SYSDATE FROM DUAL(SELECT LOCALTIMESTAMPfor PostgreSQL, etc) returns something, what you do not expect, in that case Hibernate will start adjusting non-timezone-aware JDBC data to something more or less reliable for application - that is exactly what you are observing (when I retrieve timestamps, they are transformed into default timezone)At second, any speculations around JSR-310 and JDBC 4.2 (like for timezone-aware java types you need to define DB columns as
timestamp with time zone), are not correct in case of Hibernate 5, that is mentioned in the corresponding CR as well:And indeed, if you try to find usage of
java.sql.Types#TIMESTAMP_WITH_TIMEZONEin Hibernate 5 sources you will find nothing, just because that time Hibernate developers didn't get a common opinion about how timezone conversions should work in cases of different Java versions, Java types, DB engines and JDBC drivers (they are developing the most popular (mine: the only one) JPA implementation, that is definitely not the same as develop microservice), however, there are a lot of related changes in Hibernate 6 (check TimeZoneStorageType for example). In Hibernate 5 all timezone conversion logic passes through TimestampTypeDescriptor:and as you can see, Hibernate 5 just gives a hint to JDBC driver, how the last should process
#getTimestampcall:in regard to your case:
you either need to use timezone-aware java types (
ZonedDateTime/OffsetDateTime, or evenInstant) or code your own Hibernate type, which will handle timezone conversions - that is not so hard as it might seem.