Spring Data JPA and ZonedDateTime
My database had a couple of timestamp
columns that I wanted to
display in ISO8601 format, which is a very popular format for date/time, and in particular it is handled very easily in Javascript. This is especially interesting when considering REST APIs or, as in our case, GraphQL servers that must support an array of frameworks and clients.
First of all, I have to say that
manipulating java.sql.Timestamps is by far the easiest way to work
with timestamp
type columns and spring-data-jpa
Specifications. Operations such as CriteriaBuilder
greatThanOrEqualTo
can be performed
right on the Hibernate entity attributes, as JPA knows to perform the proper conversions and produce proper SQL. If this stuff gets confusing I highly recommend this guide.
Otherwise, even using simple native queries (using JdbcTemplate
or just PreparedStatement
), using Timestamp.from
is just as easy.
Then, converting to ZonedDateTime is easy. Let’s print one while we’re at it:
1 | ZonedDateTime t = timestamp.toInstant().atZone(ZonedId.systemDefault()); |
2018-04-16T08:12:59.626+03:00[Asia/Jerusalem]
While this may be compliant with ISO8601, the presence of the
timezone name (ZoneId
) may be redundant, even though the
documentation states that the offset prevails in case of
discrepancy.
Thankfully, there is another class, OffsetDateTime, which, as its name indicates, represents a date and time with an offset, but without a ZoneId. If we wanted to reproduce the former output without the ZoneId we could do:
1 | ZonedDateTime t = timestamp.toInstant().atZone(ZonedId.systemDefault()); |
Or directly:
1 | OffsetDateTime t = OffsetDateTime.ofInstant(timestamp.toInstant(), ZonedId.systemDefault()); |
Note that you may lose the beauty of using Instant.atZone
, but you get to use the object that you need.