jpa-spec
  1. jpa-spec
  2. JPA_SPEC-63

JPA next should support Java 8 Date and Time types

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: 2.2
    • Labels:
      None

      Description

      Currently, JPA temporal fields are supported for the following data types: java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time, and java.sql.Timestamp. java.sql.Date properties are always mapped to the JDBC methods getDate and setDate, and it is an error to specify the @javax.persistence.Temporal annotation for these types. The same is true of Time (mapped to getTIme and setTime) and Timestamp (mapped to getTimestamp and setTimestamp). Properties of type java.util.Date and Calendar must be annotated with @Temporal to specify the javax.persistence.TemporalType enum indicating which JDBC methods should be used for those properties.

      Some vendors support other temporal types, such as Joda Time, but this is non-standard and should probably remain so since Joda Time isn't guaranteed to stay around (and, in fact, is likely to start ramping down with the release of Java 8).

      JSR-310 as part of Java 8 specifies a new Date & Time API in the java.time package and sub-packages that supplants java.util.Date, Calendar, java.sql.Date, Time, Timestamp, and Joda Time. It is based off of the Joda Time API, but with enhancements and certain redesigns that the Joda Time founder/creator has said makes it superior to Joda Time.

      JPA's existing rules for the currently-supported temporal types should remain largely unchanged. However, the specification should be added to in order to specify support for JSR-310. These are the proposed new rules I believe should be present in the JPA.next specification:

      • Properties of type java.time.Duration are treated as @javax.persistence.Basic fields. They automatically map to;
        • DURATION fields if the database vendor supports duration types;
        • DECIMAL-type fields storing the seconds before the decimal point and the nanoseconds after the decimal point;
        • INTEGER-type fields storing the seconds; and,
        • CHAR/VARCHAR-type fields storing the value in its ISO-8601 format (Duration#toString() and Duration#parse(CharSequence)).
      • Properties of type java.time.Period are treated as @Basic fields. They automatically map to:
        • PERIOD or DURATION fields if the database vendor supports period or duration types;
        • DECIMAL-type fields storing the seconds before the decimal point and the nanoseconds after the decimal point;
        • INTEGER-type fields storing the seconds; and,
        • CHAR/VARCHAR-type fields storing the value in its ISO-8601 format (Period#toString() and Period#parse(CharSequence)).
      • Properties of type java.time.Year are treated as @Basic fields. They automatically map to:
        • YEAR fields if the database vendor supports year types; and,
        • INTEGER/CHAR/VARCHAR-type fields storing the literal number/string value.
      • Properties of enum type java.time.Month are treated as special-case enum fields.
        • If the database field is a MONTH field (assuming the database vendor supports such types), it maps to this field.
        • If @javax.persistence.Enumerated is not present and the database field is an INTEGER-type field, it maps as the month number (NOT the ordinal) using int Month#getValue() and Month Month#of(int).
        • Otherwise, it falls back to standard enum mapping rules.
        • It is an error to annotate a Month property with @Enumerated if the database field is of type MONTH.
      • Properties of enum type java.time.DayOfWeek are treated as special-case enum fields.
        • If the database field is a DAY_OF_WEEK field (assuming the database vendor supports such types), it maps to this field.
        • If @Enumerated is not present and the database field is an INTEGER-type field, it maps as the day number (NOT the ordinal) using int DayOfWeek#getValue() and DayOfWeek DayOfWeek#of(int).
        • Otherwise, it falls back to standard enum mapping rules.
        • It is an error to annotate a DayOfWeek property with @Enumerated if the database field is of type DAY_OF_WEEK.
      • Properties of type java.time.YearMonth are treated as @Basic fields.
        • By default, they automatically map to:
          • YEARMONTH fields if the database vendor supports year-month types;
          • DATE and DATETIME fields storing the lowest day number that the database vendor supports and zero-time if applicable; and,
          • CHAR/VARCHAR-type fields storing the value in its ISO-8601 format (YearMonth#toString() and YearMonth#parse(CharSequence)).
        • The new @javax.persistence.YearMonthColumns annotation can map a YearMonth property to two database fields. A property annotated with this overrides the default mapping behavior. It is an error to mark properties of any other type with this annotation. The required @javax.persistence.Column-typed year attribute specifies the column that the year is stored in while the required @Column-typed month attribute specifies the column that the month is stored in. The year column follows the same default mapping rules as for Year types and the month column as for the Month enum. It is an error to specify @Column and @YearMonthColumns on the same property.
      • Properties of type java.time.MonthDay are treated as @Basic fields.
        • By default they automatically map to:
          • MONTHDAY fields if the database vendor supports month-day types;
          • DATE and DATETIME fields storing the lowest year number that the database vendor supports and zero-time if applicable; and,
          • CHAR/VARCHAR-type fields storing the value in its ISO-8601 format (MonthDay#toString() and MonthDay#parse(CharSequence).
        • The new @javax.persistence.MonthDayColumns annotation can map a MonthDay property to two database fields. A property annotated with this overrides the default mapping behavior. It is an error to mark properties of any other type with this annotation. The required @Column-typed month attribute specifies the column that the month is stored in while the required @Column-typed day attribute specifies the column that the day is stored in. The month column follows the same default mapping rules as for the Month enum and the day column automatically maps to INTEGER/CHAR/VARCHAR-type fields. It is an error to specify @Column and @MonthDayColumns on the same property.
      • Properties of type java.time.ZoneId are treated as @Basic fields. They automatically map to:
        • TIMEZONE fields if the database vendor supports time zone types (they never map to offset fields); and,
        • CHAR/VARCHAR-type fields storing the value in its ISO-8601 format (ZoneId#toString() and ZoneId#of(String)).
      • Properties of type java.time.ZoneOffset are treated as @Basic fields. They automatically map to:
        • OFFSET fields if the database vendor supports offset types (they never map to time zone fields); and,
        • CHAR/VARCHAR-type fields storing the value in its ISO-8601 format (ZoneOffset#toString() and ZoneOffset#of(String)).
      • Properties of types java.time.Instant, java.time.LocalDate, java.time.LocalTime, java.time.LocalDateTime, java.time.OffsetTime, java.time.OffsetDateTime, and java.time.ZonedDateTime are treated as temporal @Basic types that are mapped using the following rules:
        • LocalDate always maps as a date-only value. It is an error to mark a LocalDate property with the @Temporal annotation.
        • LocalTime and OffsetTime always map as time-only values. It is an error to mark a LocalTime or OffsetTime property with the @Temporal annotation.
        • Instant, LocalDateTime, OffsetDateTime, and ZonedDateTime map as timestamp values by default. You may mark a property of one of these types with @Temporal to specify a different strategy for persisting that property.
        • The new @javax.persistence.TemporalIncludeTimeZone annotation indicates that the offset in the OffsetTime or OffsetDateTime property or the time zone in the ZonedDateTime or Calendar property will be persisted with the value. Otherwise (if this is absent) the value is converted to the database server offset or time zone for persistence.
        • The new @javax.persistence.TemporalTimeZoneColumn(@Column value) annotation indicates a different column in which the time zone value is stored. It implies @TemporalIncludeTimeZone. It is required if @TemporalIncludeTimeZone is present but the database vendor does not support storing the time zone with the field data type. It is also required if @TemporalIncludeTimeZone is present but the JDBC driver in use is less than version 4.2 (a JDBC 4.2 driver is necessary to persist time zones and offsets with time/date-time values). The persistence rules for this column are the same as for ZoneId and ZoneOffset properties.
        • Properties of these types invoke the following special handling for JDBC driver versions before and after 4.2.
          • A JDBC driver is considered version 4.2 or better if java.sql.Driver#getMajorVersion() returns a number greater than 4, or it returns 4 and Driver#getMinorVersion() returns a number greater than 1. In the absence of a testable Driver instance, implementations may assume that the driver version is less than 4.2 if PreparedStatement#setObject(int, Object, SQLType) throws a SQLFeatureNotSupportedException.
          • If the JDBC driver is version 4.2 or newer, these seven types are persisted and retrieved as follows:
            • They are persisted with PreparedStatement#setObject(int, Object, SQLType) and retrieved with ResultSet#getObject(int, Class<?>) or ResultSet#getObject(String, Class<?>).
            • Time-only properties or TemporalType.TIME properties use a java.sql.SQLType of java.sql.JDBCType.TIME in the absence of @TemporalIncludeTimeZone or presence of @TemporalTimeZoneColumn. They use JDBCType.TIME_WITH_TIMEZONE in the presence of @TemporalIncludeTimeZone and absence of @TemporalTimeZoneColumn.
            • Date-only properties or TemporalType.DATE properties use a SQLType of JDBCType.DATE.
            • Date-and-time properties use a SQLType of JDBCType.TIMESTAMP in the absence of @TemporalIncludeTimeZone or presence of @TemporalTimeZoneColumn. They use JDBCType.TIMESTAMP_WITH_TIMEZONE in the presence of @TemporalIncludeTimeZone and absence of @TemporalTimeZoneColumn.
          • If the JDBC driver is version 4.1 or older, these seven types are persisted and retrieved as follows:
            • Time-only properties or TemporalType.TIME properties are automatically converted to and from Time and use the traditional setTime and getTime methods.
            • Date-only properties or TemporalType.DATE properties are automatically converted to and from java.sql.Date and use the traditional setDate and getDate methods.
            • Date-and-time properties are automatically converted to and from Timestamp and use the traditional setTimestamp and getTimestamp methods.
            • @TemporalTimeZoneColumn is required if @TemporalIncludeTimeZone is present.

        Activity

        Hide
        richardwalker added a comment -

        Please consider including support for a "pure UTC" data flow at least in the following specific sense:

        • Java default time zone can be set to anything (to be specific, not UTC)
        • Some of the attributes of an entity class are specified as LocalDateTime, where the values are considered to be in UTC
        • Schema generation makes database columns of a "TIMESTAMP-like" type (actually, for MySQL I would override and use DATETIME in order to get a wider range of values)
        • Values are sent back/forth to the database "as is"
        • At no point do the values get converted to/from the default time zone (or any other time zone), so as to avoid the issue with confusion of values during daylight saving changeover

        I don't see how to achieve this with JPA as is.

        Until yesterday I have been using an AttributeConverter like this, based on code that can be found on several blogs:

        @Converter(autoApply = true)
        public class LocalDateTimeConverter implements
            AttributeConverter<LocalDateTime, Timestamp> {
        
            @Override
            public Timestamp convertToDatabaseColumn(
                    final LocalDateTime attribute) {
                if (attribute == null) {
                    return null;
                }
                return Timestamp.valueOf(attribute);
            }
        
            @Override
            public LocalDateTime convertToEntityAttribute(
                    final Timestamp dbData) {
                if (dbData == null) {
                    return null;
                }
                return dbData.toLocalDateTime();
            }
        }
        

        I now realise that although this seems to work, it is wrong, because both Timestamp.valueOf() and Timestamp.toLocalDateTime() interpret the value as though it were in the default time zone, so the code breaks during daylight saving changeover when there's an hour of time that doesn't "exist" in the default time zone.

        For example, consider the test value 2016-10-02 02:02:01, which is a perfectly valid time when interpreted as UTC, but which does not exist in my local time zone (Australia/Sydney). If I (with default time zone Australia/Sydney) use the above converter to persist the LocalDateTime value LocalDateTime.of(2016, 10, 2, 2, 1, 0), the value is sent to the database, and stored, as '2016-10-02 03:01:00.0', and when it is read back into a LocalDateTime, its value is now one hour out! (I've done exactly this test to confirm.)

        My converter is now like this:

        @Converter(autoApply = true)
        public class LocalDateTimeConverter implements
            AttributeConverter<LocalDateTime, Timestamp> {
        
            @Override
            public Timestamp convertToDatabaseColumn(
                    final LocalDateTime attribute) {
                if (attribute == null) {
                    return null;
                }
                return Timestamp.from(attribute.toInstant(ZoneOffset.UTC));
            }
        
            @Override
            public LocalDateTime convertToEntityAttribute(
                    final Timestamp dbData) {
                if (dbData == null) {
                    return null;
                }
                return LocalDateTime.ofInstant(dbData.toInstant(), ZoneOffset.UTC);
            }
        }
        

        but this doesn't work as is; it requires the recently-added Hibernate-specific configuration (explained at http://in.relation.to/2016/09/12/jdbc-time-zone-configuration-property/) to specify using UTC when sending Timestamp values through JDBC:

        hibernate.jdbc.time_zone=UTC
        

        So, although LocalDateTime values are "in theory" separate from concerns about time zones, it seems that when it comes to persisting them as Timestamp values, the values must be interpreted as being in some time zone.

        So, please consider providing some way of specifying that LocalDateTime values are persisted in a "transparent" way (avoiding all internal time zone conversions along the way), or, if that is not possible, specifying the time zone in which LocalDateTime values are to be interpreted.

        Show
        richardwalker added a comment - Please consider including support for a "pure UTC" data flow at least in the following specific sense: Java default time zone can be set to anything (to be specific, not UTC) Some of the attributes of an entity class are specified as LocalDateTime , where the values are considered to be in UTC Schema generation makes database columns of a "TIMESTAMP-like" type (actually, for MySQL I would override and use DATETIME in order to get a wider range of values) Values are sent back/forth to the database "as is" At no point do the values get converted to/from the default time zone (or any other time zone), so as to avoid the issue with confusion of values during daylight saving changeover I don't see how to achieve this with JPA as is. Until yesterday I have been using an AttributeConverter like this, based on code that can be found on several blogs: @Converter(autoApply = true ) public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> { @Override public Timestamp convertToDatabaseColumn( final LocalDateTime attribute) { if (attribute == null ) { return null ; } return Timestamp.valueOf(attribute); } @Override public LocalDateTime convertToEntityAttribute( final Timestamp dbData) { if (dbData == null ) { return null ; } return dbData.toLocalDateTime(); } } I now realise that although this seems to work, it is wrong, because both Timestamp.valueOf() and Timestamp.toLocalDateTime() interpret the value as though it were in the default time zone, so the code breaks during daylight saving changeover when there's an hour of time that doesn't "exist" in the default time zone. For example, consider the test value 2016-10-02 02:02:01, which is a perfectly valid time when interpreted as UTC, but which does not exist in my local time zone (Australia/Sydney). If I (with default time zone Australia/Sydney) use the above converter to persist the LocalDateTime value LocalDateTime.of(2016, 10, 2, 2, 1, 0) , the value is sent to the database, and stored, as '2016-10-02 03:01:00.0', and when it is read back into a LocalDateTime , its value is now one hour out! (I've done exactly this test to confirm.) My converter is now like this: @Converter(autoApply = true ) public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> { @Override public Timestamp convertToDatabaseColumn( final LocalDateTime attribute) { if (attribute == null ) { return null ; } return Timestamp.from(attribute.toInstant(ZoneOffset.UTC)); } @Override public LocalDateTime convertToEntityAttribute( final Timestamp dbData) { if (dbData == null ) { return null ; } return LocalDateTime.ofInstant(dbData.toInstant(), ZoneOffset.UTC); } } but this doesn't work as is; it requires the recently-added Hibernate-specific configuration (explained at http://in.relation.to/2016/09/12/jdbc-time-zone-configuration-property/ ) to specify using UTC when sending Timestamp values through JDBC: hibernate.jdbc.time_zone=UTC So, although LocalDateTime values are "in theory" separate from concerns about time zones, it seems that when it comes to persisting them as Timestamp values, the values must be interpreted as being in some time zone. So, please consider providing some way of specifying that LocalDateTime values are persisted in a "transparent" way (avoiding all internal time zone conversions along the way), or, if that is not possible, specifying the time zone in which LocalDateTime values are to be interpreted.
        Hide
        braghest added a comment -

        richardwalker you're using UTC in the database and something else (eg. Australia/Sydney) in the JVM. I would strongly advise against when using LocalDateTime.
        To illustrate the point imagine you have 2017-04-02 02:50:00+11:00 and 2017-04-02 02:10:00+10:00 two instants, 20 minutes apart. Now because you're using LocalDateTime as input and because your JVM time zone isn't UTC what you tell the database to store is 2017-04-02 02:50:00 and 2017-04-02 02:10:00. Note that now the dates are in a different order and 40 minutes apart. You have silent data truncation.
        Normally I would recommend to use TIMESTAMP WITH TIME ZONE even if you're using UTC, unfortunately MySQL doesn't support that yet.

        Since you're using Hibernate I would normally recommend you use a UserType instead of an AttributeConverter since it gives you direct access to the PreparedStatement and ResultSet. If the driver supports JSR-310 data types you can use them natively without converting. Unfortunately Connector / J currently converts through java.sql types which still leaves it vulnerable to the issues you observed.

        Until this issue is fixed I would recommend you:

        • use OffsetDateTime or ZonedDateTime in your application, then first convert to UTC and then to LocalDateTime
        • use a Hibernate UserType and pass the java.time types to the driver
        • test with timestamps during both winter → summer time and summer → winter time transitions
        • consider running your JVM in UTC
        Show
        braghest added a comment - richardwalker you're using UTC in the database and something else (eg. Australia/Sydney) in the JVM. I would strongly advise against when using LocalDateTime . To illustrate the point imagine you have 2017-04-02 02:50:00+11:00 and 2017-04-02 02:10:00+10:00 two instants, 20 minutes apart. Now because you're using LocalDateTime as input and because your JVM time zone isn't UTC what you tell the database to store is 2017-04-02 02:50:00 and 2017-04-02 02:10:00 . Note that now the dates are in a different order and 40 minutes apart. You have silent data truncation. Normally I would recommend to use TIMESTAMP WITH TIME ZONE even if you're using UTC, unfortunately MySQL doesn't support that yet. Since you're using Hibernate I would normally recommend you use a UserType instead of an AttributeConverter since it gives you direct access to the PreparedStatement and ResultSet . If the driver supports JSR-310 data types you can use them natively without converting. Unfortunately Connector / J currently converts through java.sql types which still leaves it vulnerable to the issues you observed. Until this issue is fixed I would recommend you: use OffsetDateTime or ZonedDateTime in your application, then first convert to UTC and then to LocalDateTime use a Hibernate UserType and pass the java.time types to the driver test with timestamps during both winter → summer time and summer → winter time transitions consider running your JVM in UTC
        Hide
        richardwalker added a comment -

        To illustrate the point imagine you have 2017-04-02 02:50:00+11:00 and 2017-04-02 02:10:00+10:00 two instants, 20 minutes apart.

        But I wouldn't (and I don't).

        As I wrote:

        Some of the attributes of an entity class are specified as LocalDateTime, where the values are considered to be in UTC

        So I would have – following the values in your example – two LocalDateTime values LocalDateTime.of(2017, 4, 1, 15, 50, 0) and LocalDateTime.of(2017, 4, 1, 16, 10, 0). And I would want those to be persisted in my database, in columns of type DATETIME, as the values '2017-04-01 15:50:00' and '2017-04-01 16:10:00'. And when they are read back in, they are converted back into the original LocalDateTime values.

        And with the combination of:

        • the second version of the LocalDateTimeConverter class
        • the Hibernate-specific setting hibernate.jdbc.time_zone=UTC

        this is the behaviour I get.

        I think I do not actually need a "solution" to my problem: I now seem to have one that works. The point of my first message is that the particular combination of the five dot points at the top of the message seems not to be currently achievable with "pure" JPA (i.e., without Hibernate-specific settings).

        You have mostly offered both non-alternatives (e.g., setting the JVM's timezone to UTC, which, at least for now, I can not do), and alternatives that also do not use "pure" JPA!

        I do thank you for suggesting to have a look at ZonedDateTime and OffsetDateTime. From a modelling point of view, these two classes allow modelling the fact that the values in my program do belong to a particular time zone (i.e., UTC).

        So, if you don't like my use of LocalDateTime, I now present the original problem, modified to use ZonedDateTime.

        I want a solution that has all of these features:

        • Java default time zone can be set to anything (to be specific, not UTC)
        • Some of the attributes of an entity class are specified as ZonedDateTime, where the ZoneOffset of the values is UTC
        • Schema generation makes database columns of a "TIMESTAMP-like" type (actually, for MySQL I would override and use DATETIME in order to get a wider range of values)
        • Values are sent back/forth to the database as UTC values
        • At no point do the values get converted to/from the default time zone (or any other time zone), so as to avoid the issue with confusion of values during daylight saving changeover

        And again: I don't see how to achieve this with JPA as is.

        Here is the converter class using ZonedDateTime:

        @Converter(autoApply = true)
        public class ZonedDateTimeConverter implements
            AttributeConverter<ZonedDateTime, Timestamp> {
        
            @Override
            public Timestamp convertToDatabaseColumn(
                    final ZonedDateTime attribute) {
                if (attribute == null) {
                    return null;
                }
                return Timestamp.from(attribute.toInstant());
            }
        
            @Override
            public ZonedDateTime convertToEntityAttribute(
                    final Timestamp dbData) {
                if (dbData == null) {
                    return null;
                }
                return ZonedDateTime.ofInstant(dbData.toInstant(), ZoneOffset.UTC);
            }
        }
        

        And again, this doesn't work as is, for the same reason as before: the converted Timestamp values are persisted in the local time zone, not in UTC. The Hibernate-specific setting hibernate.jdbc.time_zone=UTC is still required to make it work. I conclude: the Hibernate-specific property hibernate.jdbc.time_zone=UTC does actually solve a problem; it is not "syntactic sugar" for something you can do another way in "pure" JPA.

        So maybe it boils down to: please add a JPA setting that achieves what hibernate.jdbc.time_zone=UTC does. And maybe consider making the application of the setting scope-able (e.g., to individual fields).

        Show
        richardwalker added a comment - To illustrate the point imagine you have 2017-04-02 02:50:00+11:00 and 2017-04-02 02:10:00+10:00 two instants, 20 minutes apart. But I wouldn't (and I don't). As I wrote: Some of the attributes of an entity class are specified as LocalDateTime, where the values are considered to be in UTC So I would have – following the values in your example – two LocalDateTime values LocalDateTime.of(2017, 4, 1, 15, 50, 0) and LocalDateTime.of(2017, 4, 1, 16, 10, 0) . And I would want those to be persisted in my database, in columns of type DATETIME , as the values '2017-04-01 15:50:00' and '2017-04-01 16:10:00' . And when they are read back in, they are converted back into the original LocalDateTime values. And with the combination of: the second version of the LocalDateTimeConverter class the Hibernate-specific setting hibernate.jdbc.time_zone=UTC this is the behaviour I get. I think I do not actually need a "solution" to my problem: I now seem to have one that works. The point of my first message is that the particular combination of the five dot points at the top of the message seems not to be currently achievable with "pure" JPA (i.e., without Hibernate-specific settings). You have mostly offered both non-alternatives (e.g., setting the JVM's timezone to UTC, which, at least for now, I can not do), and alternatives that also do not use "pure" JPA! I do thank you for suggesting to have a look at ZonedDateTime and OffsetDateTime . From a modelling point of view, these two classes allow modelling the fact that the values in my program do belong to a particular time zone (i.e., UTC). So, if you don't like my use of LocalDateTime , I now present the original problem, modified to use ZonedDateTime . I want a solution that has all of these features: Java default time zone can be set to anything (to be specific, not UTC) Some of the attributes of an entity class are specified as ZonedDateTime , where the ZoneOffset of the values is UTC Schema generation makes database columns of a "TIMESTAMP-like" type (actually, for MySQL I would override and use DATETIME in order to get a wider range of values) Values are sent back/forth to the database as UTC values At no point do the values get converted to/from the default time zone (or any other time zone), so as to avoid the issue with confusion of values during daylight saving changeover And again: I don't see how to achieve this with JPA as is. Here is the converter class using ZonedDateTime : @Converter(autoApply = true ) public class ZonedDateTimeConverter implements AttributeConverter<ZonedDateTime, Timestamp> { @Override public Timestamp convertToDatabaseColumn( final ZonedDateTime attribute) { if (attribute == null ) { return null ; } return Timestamp.from(attribute.toInstant()); } @Override public ZonedDateTime convertToEntityAttribute( final Timestamp dbData) { if (dbData == null ) { return null ; } return ZonedDateTime.ofInstant(dbData.toInstant(), ZoneOffset.UTC); } } And again, this doesn't work as is, for the same reason as before: the converted Timestamp values are persisted in the local time zone, not in UTC. The Hibernate-specific setting hibernate.jdbc.time_zone=UTC is still required to make it work. I conclude: the Hibernate-specific property hibernate.jdbc.time_zone=UTC does actually solve a problem; it is not "syntactic sugar" for something you can do another way in "pure" JPA. So maybe it boils down to: please add a JPA setting that achieves what hibernate.jdbc.time_zone=UTC does. And maybe consider making the application of the setting scope-able (e.g., to individual fields).
        Hide
        braghest added a comment -

        richardwalker You're correct, I missed that part

        Some of the attributes of an entity class are specified as LocalDateTime, where the values are considered to be in UTC

        and in this case your code works as long as everybody remembers that in your application for your entities LocalDateTime means UTC.

        Once somebody writes

        LocalDate.now()
        

        instead of

        LocalDate.now(ZoneOffset.UTC)
        

        it breaks.

        The last converter you posted fixes this.

        Show
        braghest added a comment - richardwalker You're correct, I missed that part Some of the attributes of an entity class are specified as LocalDateTime, where the values are considered to be in UTC and in this case your code works as long as everybody remembers that in your application for your entities LocalDateTime means UTC. Once somebody writes LocalDate.now() instead of LocalDate.now(ZoneOffset.UTC) it breaks. The last converter you posted fixes this.
        Hide
        richardwalker added a comment -

        For anyone reading this who wants to use my code, note that for MySQL you'll need to add these parameters to the JDBC URL:

        &serverTimezone=UTC&useLegacyDatetimeCode=false

        otherwise you "fall at the last hurdle" (i.e., the JDBC driver ruins everything when it converts Timestamp values to strings).

        Other databases may require something similar.

        Show
        richardwalker added a comment - For anyone reading this who wants to use my code, note that for MySQL you'll need to add these parameters to the JDBC URL: &serverTimezone=UTC&useLegacyDatetimeCode=false otherwise you "fall at the last hurdle" (i.e., the JDBC driver ruins everything when it converts Timestamp values to strings). Other databases may require something similar.

          People

          • Assignee:
            Unassigned
            Reporter:
            Nick Williams
          • Votes:
            56 Vote for this issue
            Watchers:
            43 Start watching this issue

            Dates

            • Created:
              Updated: