Best way to store timezone-independent time in JPA MySql

2020-02-15 java mysql sql spring-boot spring-data-jpa

I can't find a good solution in JPA to store timezone-independent time in a mysql db.

I have a shift table, where I need to store the start and the end time for each shift.

+-------------+--------------+------+-----+----------+----------------+
| Field       | Type         | Null | Key | Default  | Extra          |
+-------------+--------------+------+-----+----------+----------------+
| id          | int(11)      | NO   | PRI | NULL     | auto_increment |
| name        | varchar(64)  | NO   |     | NULL     |                |
| start_time  | time         | NO   |     | 00:00:00 |                |
| end_time    | time         | NO   |     | 00:00:00 |                |
+-------------+--------------+------+-----+----------+----------------+

So, the start/end times retrived from mysql have to be treated as strings (without applying a particular timezone). But if I store them as varchar(8) I cannot use the following query (without applying any type conversion from varchar to time).

select * from shift where ('21:30:00' BETWEEN start_time and end_time );

So, I want to preserve the ability to compare them as times.

I tried to model the shift table as following:

    @Entity
    public class Shift {
      @Id
      private Long id;

      @Column(name = "name")
      private String name;

      @Column(name = "start_time")
      private LocalTime startTime;

      @Column(name = "end_time")
      private LocalTime endTime;

...

The start_time and the end_time are mapped as LocalTime because the LocalTime doesn't store the timezone info. But, Hibernate convert the java.util.Date of each record retrived to a LocalTime applying the system default timezone, as following:

    if ( Date.class.isInstance( value ) ) {
        final Date ts = (Date) value;
        final Instant instant = Instant.ofEpochMilli( ts.getTime() );
        return LocalDateTime.ofInstant( instant, ZoneId.systemDefault() ).toLocalTime();
    }

So, the resulting start/end time is relative to the timezone of the server.

A solution is to store them as integers and split hours from minutes. In this way, the shift table will have four columns: start_hours, start_minutes, end_hours, end_minutes. But it's tedious to make query using them in JPA. There is a better solution?

UPDATE

I have to fetch the current shift using the timezone of the server. So, if I store times as UTC in the DB and then I query them converting the current server time to UTC doesn't work because during the Daylight Saving Time (DST) the server timezone increases by one. So, in the winter the 07:00:00+01 is converted to 06:00:00 UTC. But, in the summer 07:00:00+02 is converted to 05:00:00 UTC.

Answers

Welcome to SO

It's always better to store dates with UTC TimeZone in database and do the conversion on client-side. You can set below property to force JPA To use UTC

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

Hope this hleps

You can take a look at this blog

Related