0

We have a bunch of code that gets a DateTime from JDBC, Saxon (XPath), dom4j, jway json-path (JPath), & OData as a Date object. We're now up on Java 1.8 and my first question is do I want to now try to get any data that I used to get as a Date object to now get it as a ZonedDateTime object? Or should I be using something else?

My second question is how do I read the data from JDBC, Saxon, etc as ZonedDateTime objects?

David Thielen
  • 28,723
  • 34
  • 119
  • 193
  • Your question is too broad and should really be asked per technology. JDBC has nothing to do with Saxon has nothing to do with jsonpath has nothing to do with etc.. For example the answer for JDBC is "you can't, at least not directly, as JDBC (since 4.2) only specifies a mapping for LocalDate/LocalTime/LocalDateTime/OffsetTime/OffsetDateTime and not for ZonedDateTime." No clue about the others. – Mark Rotteveel Jul 28 '18 at 12:30

1 Answers1

4

tl;dr

  • Never use the legacy classes, use only java.time.
  • When you must, convert using new methods added to the old classes.
  • As of JDBC 4.2, exchange java.time objects with your database, never strings or java.sql types.
  • Do most of your work in UTC. Adjust into a time zone only for presentation.
  • When communicating date-time values as text, use ISO 8601 formats.
  • Search Stack Overflow for more info.

Avoid legacy date-time classes

The terribly troublesome old date-time classes such as java.util.Date, java.util.Calendar, java.text.SimpleDateFormat, java.sql.Timestamp, and java.sql.Date are all entirely supplanted by the java.time classes. No need to ever touch those awful old classes again.

The java.time classes have been bundled with Java 8 and later for a few years now. They have proven themselves to be a reliable, industry-leading framework for date-time work. They were inspired by the lessons learned from the excellent Joda-Time project (now in maintenance-mode). So the java.time classes have “an old soul”, and are not some limited “1.0” rough draft.

Conversion

For interoperating with old code not yet updated to the java.time classes, you can easily convert back-and-forth between the legacy classes and modern classes. For conversions, look to new methods added to the old classes. Read Questions such as this to learn more.

Database

As of JDBC 4.2 and later, you can directly exchange java.time objects with your database. No need to ever use the badly-designed java.sql classes again for date-time values.

Generally best to use Instant for values in a column of type akin to the SQL-standard TIMESTAMP WITH TIME ZONE.

myPreparedStatement.setObject( … , instant ) ;

And retrieval.

Instant instant = myResultSet.getObject( … , Instant.class ) ;

ISO 8601

When exchanging date-time values outside of a JVM, serialize to text using the standard ISO 8601 formats. These formats are designed to be useful and practical, easy to parse by machines, easy to read by humans across cultures.

The java.time classes use the ISO 8601 formats by default when parsing/generating strings. The ZonedDateTime class extends the standard by wisely appending the name of the zone in square brackets.

Zones

data that I used to get as a Date object to now get it as a ZonedDateTime object?

The java.util.Date class is directly replaced by Instant. Both represent a moment in UTC. The modern class resolves to nanoseconds instead of milliseconds.

Instant instant = myJavaUtilDate.toInstant() ;  // Convert from legacy class to modern. 

In databases such as Postgres, a column of type TIMESTAMP WITH TIME ZONE actually does not have its time zone saved. Instead, any offset or zone passed with an incoming value is used by the database to adjust into UTC. The resulting UTC moment is saved to the database, and the original zone/offset is discarded. If you need the original zone/offset, you must manually save it to an extra column yourself.

So, generally best to pass and fetch Instant objects with your database for a moment on the timeline.

To learn about the concept of a date-time not on the timeline, search for LocalDateTime class, and read postings like this Question, What's the difference between Instant and LocalDateTime?.

Be aware that the SQL standard barely touches on the tricky topic of date-time handling. It defines a few types but says little about behavior. So databases vary widely in their implementations. Be sure to study and experiment to verify your understanding of your database and driver.

read the data from JDBC, Saxon, etc as ZonedDateTime objects?

Generally the best practice is to work in UTC. That means the Instant class rather than ZonedDateTime class.

If receiving a Date, convert to Instant as shown above.

Usually you want to do your business logic, storage, exchange, logging, and tracing/debugging all in UTC. Apply a time zone only where required by business requirements or for presentation to a user.

With a Instant in hand, you can adjust to the wall-clock time used by the people of a particular region by assigning a time zone. Apply a ZoneId to get a ZonedDateTime.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

Search Stack Overflow

Your Question is really a duplicate of many others such as this. I suggest you search Stack Overflow for the various java.time class names. You will learn much as there have been plenty of questions and answers already posted.

Compatible libraries

Many Java libraries have been updated to work with java.time types.

Check for the latest versions of libraries you may be using, and read their documentation to learn about added support.

If not directly supported, libraries that accept converters/formatters/plugins will likely have some java.time ones already written. Search for them, or ask on the sister site: Software Recommendations Stack Exchange.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Really helpful post. Question, why Instant instead of ZonedDateTime? TIA – David Thielen Jul 27 '18 at 23:07
  • 1
    Excellent response, and a reminder that with the next release of Saxon moving to a Java 8 baseline, we should look again at what conversions from XDM date/time types to Java types we support. – Michael Kay Jul 28 '18 at 08:20
  • 1
    If `Date` fulfilled your requirements in the old days, `Instant` will now. Only if you need to store a specific time zone (like Africa/Juba) (which `Date` could not do), use `ZonedDateTime`. – Ole V.V. Jul 28 '18 at 09:16