Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JPA next should support Java 8 Date and Time types #63

Closed
lukasj opened this issue Aug 11, 2013 · 25 comments
Closed

JPA next should support Java 8 Date and Time types #63

lukasj opened this issue Aug 11, 2013 · 25 comments

Comments

@lukasj
Copy link
Contributor

lukasj commented Aug 11, 2013

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.
@lukasj
Copy link
Contributor Author

lukasj commented Aug 11, 2013

@glassfishrobot Commented
Reported by beamerblvd

@lukasj
Copy link
Contributor Author

lukasj commented Aug 11, 2013

@glassfishrobot Commented
beamerblvd said:
To be clear, by "JPA.next" I mean JPA 2.2 unless 3.0 is next and there isn't going to be a 2.2. "Whatever is going to be in Java EE 8."

@lukasj
Copy link
Contributor Author

lukasj commented Aug 11, 2013

@glassfishrobot Commented
beamerblvd said:
A few additional notes:

  • The reason for specifying the JDBC < 4.2 vs JDBC ≥ 4.2 behavior is that, even today, some JDBC driver vendors have still not fully implemented JDBC 4.0 (Java 6), let alone JDBC 4.1 (Java 7). Unfortunately and terribly, it could be 5 or even 10 years before all driver vendors have JDBC 4.2 drivers. Therefore, JPA vendors should support both mechanisms (since the JDBC 4.2 mechanisms allow saving with timezones, which JDBC 4.1 does not).
  • It is an error if the @TemporalIncludeTimeZone or @TemporalTimeZoneColumn annotations are present on properties of any type other than Calendar, OffsetTime, OffsetDateTime, and ZonedDateTime.
  • A Calendar, OffsetTime, OffsetDateTime, or ZonedDateTime must be converted from its time zone/offset to the database server's time zone/offset on persistence if and only if neither @TemporalIncludeTimeZone nor @TemporalTimeZoneColumn are present on the property. If either of those are present, time zone/offset conversion is not necessary because the time zone/offset will be saved with the time (either using setObject or a second column). Upon retrieval from the database, neither the date/time value nor the time zone/offset value should ever be altered. It should be accepted as it comes back from the database, whether stored together in the same column or separately in two columns.

@lukasj
Copy link
Contributor Author

lukasj commented Aug 12, 2013

@glassfishrobot Commented
beamerblvd said:
Another note:

  • In addition to the int, Integer, short, Short, long, Long, and Timestamp types currently supported for @javax.persistence.Version-annotated properties, properties of type Instant may also be @Version-annotated.

@lukasj
Copy link
Contributor Author

lukasj commented Feb 20, 2014

@glassfishrobot Commented
mister__m said:
YearMonth and MonthDay columns can also be mapped to INTEGER columns.

@lukasj
Copy link
Contributor Author

lukasj commented Mar 25, 2014

@glassfishrobot Commented
reza_rahman said:
I must say this is an excellent initial analysis. For folks interested, the official Java Tutorial now has a nice trail on the Java SE 8 Date/Time API: http://docs.oracle.com/javase/tutorial/datetime/index.html. Details on JDBC 4.2 here: http://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/jdbc_42.html.

@lukasj
Copy link
Contributor Author

lukasj commented Apr 13, 2014

@glassfishrobot Commented
braghest said:
Don't do ISO-8601 formatted CHAR/VARCHAR-type fields violate 1st normal form?

@lukasj
Copy link
Contributor Author

lukasj commented Jun 2, 2014

@glassfishrobot Commented
tomdcc said:
Some databases such as Postgresql support storing time intervals [1], so the Duration and Period types should be allowed to map to such types if the underlying database supports them.

[1] http://www.postgresql.org/docs/9.3/static/datatype-datetime.html#DATATYPE-INTERVAL-INPUT

I believe that interval is an ANSI SQL standard type

@lukasj
Copy link
Contributor Author

lukasj commented Jan 14, 2015

@glassfishrobot Commented
perceptron8 said:
Properties of type java.time.MonthDay are treated as @basic fields.
By default they automatically map to:

  • ...
  • DATE and DATETIME fields storing the lowest year number that the database vendor supports and zero-time if applicable; and,
  • ...

This year must be also a leap year. Sadly, Date.valueOf(MonthDay.of(1, 1).atYear(0)) becomes "0001-01-01", so it can't be 0.

@lukasj
Copy link
Contributor Author

lukasj commented Mar 26, 2015

@glassfishrobot Commented
mkarg said:
While I indeed support this feature request due to its common purpose, there actually is no real need for it anymore, thanks to the acceptance of the adapter API proposal filed by me in https://java.net/jira/browse/JPA_SPEC-35: You can just write a simple adapter that does the type conversion at runtime. Or are you aiming on schema creation instead of just type conversion?

@lukasj
Copy link
Contributor Author

lukasj commented Mar 27, 2015

@glassfishrobot Commented
ymajoros said:
Yeah, but I think it would be a good idea to mention out-of-the box support in the spec, that providers can implement this way if they want. Otherwise, we'll end up basically having to package boiler-plate code every time we use java.time.* classes for JPA support.

@lukasj
Copy link
Contributor Author

lukasj commented Mar 27, 2015

@glassfishrobot Commented
mkarg said:
While that is absolutely correct, the technical answer is a bit more complex: What is the final predicate that makes a data type eligible for inclusion in the set of mandatory type mappings?

One could say, that predicate is "being essential" or "being of common use", but who defines what "essential" or "common use" is? See, for some applications, support for java.awt.Image and java.net.URL might be much more essential than support for LocalDate or ZonedDateTime. On the other hand, other applications might be full of LocalDate but never uses Instant. So where exactly to make the cut? This becomes particularly complex when looking at the sheer amount of types found in the JRE, and it is obvious there has to be a cut somewhere. Even JavaFX, which is bundled with the JRE, does not support Instant still in v8, so why should JPA? And looking at the current progress of Project Jigsaw, possibly the qualifying predicate might simply be answered by "all types in a particular jigsaw module"?

Anyways, it is not up to me to decide. I do support your request, and would love to see support for rather all Java Time API times, particularly for Instant and Duration, and your request has prominent supporters like for example Java Champion Arun Gupa as I learned recently. But I doubt the final answer will be as simple an satisfying as we would love to have it.

Maybe it would be better to simply set up another JSR, like "Common Data Type Conversions for the Java Platform", which provides much more mappings than just date and time, but also would not be bound to JPA but also could be used by JAXB, JAX-RS, and possibly more API that deal which the problem of transforming " to "? Having such a vehicle would really reduce boilerplate a lot.

@lukasj
Copy link
Contributor Author

lukasj commented Mar 28, 2015

@glassfishrobot Commented
braghest said:

there actually is no real need for it anymore, thanks to the acceptance of the adapter API proposal

I'm not sure. Firstly currently the RI explodes with a ClassCastException when trying to write an attribute converter mapping a java.util.Calendar database value. Secondly the spec would have to say that when mapping a java.util.Calendar the time zone of the value returned from the database is the time zone of the value on the database instead of the time zone of the Java virtual machine (like java.sql.Date). JDBC only allows to access the time zone of a value using the Java 8 Date and Time API.
If you currently want to access the timezone of a database value you need to use vendor specific extensions.

@lukasj
Copy link
Contributor Author

lukasj commented Sep 14, 2015

@glassfishrobot Commented
@lukasj said:
will try to address this in 2.2

@lukasj
Copy link
Contributor Author

lukasj commented Feb 2, 2016

@glassfishrobot Commented
neilstockton said:
The description for Period is wrong in that it implies that this type stores seconds+nanos, whilst it actually is YEAR+MONTH+DAY ("A date-based amount of time in the ISO-8601 calendar system"). Consequently it is not possible to store it in DECIMAL, and likely not INTEGER also.

@lukasj
Copy link
Contributor Author

lukasj commented Dec 15, 2016

@glassfishrobot Commented
richardwalker said:
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.

@lukasj
Copy link
Contributor Author

lukasj commented Jan 26, 2017

@glassfishrobot Commented
braghest said:
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

@lukasj
Copy link
Contributor Author

lukasj commented Jan 27, 2017

@glassfishrobot Commented
richardwalker said:

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).

@lukasj
Copy link
Contributor Author

lukasj commented Jan 27, 2017

@glassfishrobot Commented
braghest said:
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.

@lukasj
Copy link
Contributor Author

lukasj commented Feb 7, 2017

@glassfishrobot Commented
richardwalker said:
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.

@lukasj
Copy link
Contributor Author

lukasj commented May 5, 2017

@glassfishrobot Commented
This issue was imported from java.net JIRA JPA_SPEC-63

@lukasj
Copy link
Contributor Author

lukasj commented Jul 20, 2017

@lukasj Commented
as of 2.2 supported types are: java.time.LocalDate, java.time.LocalTime, java.time.LocalDateTime, java.time.OffsetTime and java.time.OffsetDateTime

@lukasj
Copy link
Contributor Author

lukasj commented Jul 21, 2017

@lukasj Commented
closing for 2.2 as common types were addressed. Feel free to open new issues for missing parts. Thank you!

@lukasj lukasj added this to the 2.2 milestone Aug 31, 2018
@lukasj lukasj self-assigned this Aug 31, 2018
@lukasj
Copy link
Contributor Author

lukasj commented Aug 31, 2018

@barrrettt
Copy link

guys i need UTC instant for my backend, Come on!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants