persistence
persistence copied to clipboard
Support for java.time.Instant
Original issue #63 mentioned support for java.time.Instant but it's missing in the final 2.2 spec. I haven't found any reason for omitting it.
I feel it's important for supporting pure UTC data flow as described in the #156. Instant already stores epoch internally so it cleanly maps to a UTC timestamp and it would simplify such use case rather than converting back and forth between different (application, database, user) time zones.
I believe that Instant as a machine-timeline view should be the recommended approach for persisting time data over LocalDateTime, OffsetDateTime, ZonedDateTime which are human-timeline views.
Hibernate supports Instant just fine already and allows changing the database timezone via hibernate.jdbc.time_zone.
- Issue Imported From: https://github.com/javaee/jpa-spec/issues/163
- Original Issue Raised By:@jacekkruger
- Original Issue Assigned To: Unassigned
@ghost Commented
Of all the java.time
types, it is Instant
that is designed exactly to represent a point in time, so it should be supported. It is also the only type that is suitable for conversion from and to java.sql.Timestamp
. Of the newly supported types LocalDate
, LocalTime
, LocalDateTime
, OffsetTime
and OffsetDateTime
, only the latter actually represents a point in time, but cannot be created from a Timestamp
alone (the offset is missing).
So if you want to persist a point of time with JPA 2.2, the following options appear to me:
- Use
java.util.Date
- Use
OffsetDateTime
, but this forces you to choose an offset for all your values. You can useZoneOffset.UTC
for all, basically reducingOffsetDateTime
to anInstant
. Also, not all popular database systems support persisting an offset along the timestamp value, so you might need to use@javax.persistence.TemporalTimeZoneColumn
, scattering the value among two columns. - Use
Instant
and an AttributeConverter, as you already could do before JPA 2.2
Supporting Instant
sounds preferable to each of these.
For others wishing Instants were supported directly, here is my code to support it using an AttributeConverter, as recommended as a stopgap by @lukasj above. `package Repository;
import javax.persistence.AttributeConverter; import javax.persistence.Converter; import java.sql.Timestamp; import java.time.Instant;
@Converter(autoApply = true) public class InstantAttributeConverter implements AttributeConverter<Instant, Timestamp> {
@Override
public Timestamp convertToDatabaseColumn(Instant instant) {
if (instant == null)
return null;
else
{
Timestamp t = Timestamp.from(instant);
return t;
}
}
@Override
public Instant convertToEntityAttribute(Timestamp timestamp) {
//System.out.println(timestamp + " " + timestamp.toInstant() + " " + timestamp.getTimezoneOffset());
return (timestamp == null ? null : timestamp.toInstant());
}
}`
@psyklopz Unfortunately this approach does not work correctly with all databases. On Microsoft SQL Server for example you will get local time instead of UTC.
@sergeykad Great point. By convention all our servers are set to UTC. When running on a local dev machine, we pass the time zone (UTC) as part of our connection string to the MySQL JDBC driver.
Maybe I worry more than I should, but I don't trust that time zone conversions done in Java are always consistent with those done in the database.
I also get uncomfortable that converting from UTC to local and back to UTC is not foolproof. In the hour before (or after) daylight savings we have a wrinkle in time.
I wish databases had no concept of time zones. That belongs in the presentation layer and not in the business layers. But I digress...
Use my sample code if and only if your database and your Java code are both running in UTC.
I am in favor of adding support for Instant to JPA specs.
@lukasj I agree that we should totally do this.
I've proposed support for Instant
and Year
in https://github.com/jakartaee/persistence/pull/434.
Note that it's clear why Instant
was left out of previous revisions of JPA: the JDBC spec does not mention it in Appendix B. But in fact there are other missing type mappings in the JDBC spec, so what I've done is also nailed down the missing type mappings.