How to specify UTC timezone for Spring Boot JPA Timestamp

oizulain :

Environment

  • Spring Boot Starter Data JPA 1.4.2
  • Eclipselink 2.5.0
  • Postgresql 9.4.1211.jre7

Problem

I am building a Spring Boot microservice that shares a Postgresql database with a different service. The database gets initialized externally (out of our control) and the datetime column type used by the other service is timestamp without time zone. Therefore, since I want all dates on the db to have the same type, having that type is a requirement for my JPA entity dates.

The way I map them on my JPA entity objects is as follows:

@Column(name = "some_date", nullable = false)
private Timestamp someDate;

The problem is that when I create a Timestamp as follows:

new java.sql.Timestamp(System.currentTimeMillis())

and I look at the database, the timestamp contains my local timezone date time, but I want to store it in UTC. This is because my default Timezone is set to 'Europe/Brussels' and JPA/JDBC converts my java.sql.Timestamp object into my timezone before putting it into the database.

Found not ideal solutions

  • TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC")); has the effect that I want to achieve, but it's not suitable because it is not specific to my service. I.e. it will affect the whole JVM or the current thread plus children.

  • Starting the application with -Duser.timezone=GMT seems to also do the job for a single instance of a running JVM. Therefore, a better solution than the previous one.

But is there a way to specify the timezone within the JPA/datasource/spring boot configuration?

oizulain :

The most appropriate workaround I could figure out for the problem is to use an AttributeConverter to convert Java 8 ZonedDateTime objects into java.sql.Timestamp objects, so that they can be mapped to the PostgreSQL timestamp without time zone type.

The reason why you need an AttributeConverter is because the Java 8/Joda time date time types are not yet compatible with JPA.

The AttributeConverter looks like this:

@Converter(autoApply = true)
public class ZonedDateTimeAttributeConverter implements AttributeConverter<ZonedDateTime, Timestamp> {

    @Override
    public Timestamp convertToDatabaseColumn(ZonedDateTime zonedDateTime) {
        return (zonedDateTime == null ? null : Timestamp.valueOf(zonedDateTime.toLocalDateTime()));
    }

    @Override
    public ZonedDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
        return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime().atZone(ZoneId.of("UTC")));
    }

}

This allows me to read the database timestamps that do not have timezone information as ZonedDateTime objects that have the UTC timezone. This way I keep the exact date time that can be seen on the db regardless of the timezone that my app runs in.

Since toLocalDateTime() also applies the system's default timezone conversion, this AttributeConverter basically cancels out the conversion applied by the JDBC driver.

Do you really need to use timestamp without timezone?

The reality is that if you are storing date time information on a time zone (even if it is UTC), the timestamp without timezone PostgreSQL type is the wrong choice. The right data type to use would be timestamp with timezone which does include the timezone information. More on this topic here.

However, if for whatever reason, you must use the timestamp without timezone, I think the ZonedDateTime approach above is a robust and consistent solution.

Are you also serializing the ZonedDateTime to JSON?

Then you are probably interested in the fact that you need at least version 2.6.0 of the jackson-datatype-jsr310 dependency for the serialization to work. More on that in this answer.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Spring boot - Entity : How to add CreatedDate (UTC timezone aware), LastModifiedDate (UTC timezone aware), CreatedBy, LastModifiedBy

Timestamp with timezone in relation to UTC

Timezone issue in Spring Boot JPA application

How to save timestamp in UTC format for Audit fields @CreatedDate, @LastModifiedDate in Spring JPA

Given a date/time and timezone, how do you convert that into a UTC timestamp?

Formatting UTC timestamp in local timezone

Timezone of ZonedDateTime changed to UTC during auto conversion of RequestBody with Spring Boot

Spring JPA Hibernate giving error updating timestamp wo timezone in postgres

How to set Timezone for DynamoDBAutogenerated timestamp in spring data

How can I specify timezone with current_timestamp in Oracle

Spring Boot: How to specify the PasswordEncoder?

Spring-boot @RequestParam annotation converts UTC timezone in request to local timezone

Parse UTC timestamp as local time, ignoring timezone

BigQuery automatically converts timestamp timezone to UTC

Convert UTC timestamp to local timezone issue in pandas

casting UTC unixtime to timestamp in the same timezone

Convert UTC timestamp to other timezone in ISO format

how to Distinct in JPA Spring boot?

How to guess the timezone of a timestamp?

How to specify prefix for all controllers in Spring Boot?

How do I specify a BeanNamingStrategy with Spring Boot?

How to specify the Launcher in Spring Boot Gradle?

How to specify a fallback request mapping in Spring Boot

How to store a java.util.Date into a MySQL timestamp field in the UTC/GMT timezone?

how can I get a custom timezone datetime from utc timestamp with javascript(node.js)

pandas.to_datetime() how to convert from local timezone to UTC unix timestamp?

Return CURRENT_TIMESTAMP value with specific timezone in Spring data JPA/Hibernate (HQL) query?

Spring JPA with criteria builder convert timestamp with timezone to local time with given time zone

How to set timezone in quarkus to UTC