Should I use java.util.Date or switch to java.time.LocalDate

Edit: Well, apparently it was too opinion based, so let me try to reword it more precisely -

Are there any clear caveats or drawbacks of using LocalDate, LocalTime etc. in a Java code that does not need any backwards compatibility, and if so - what are they?

I'm looking for things like "Current EE libraries X and Y don't work correctly with LocalDate" or "This very useful pattern is broken with LocalTime" et cetera.


(here is the original question for reference)

With Java 8, a new time API is introduced, namely the java.time.LocalDate etc., but java.util.Date is not marked as deprecated.

I am writing a new project, which does not need to be backwards compatible. Should I only use LocalDate, LocalDateTime etc.? Are there any drawbacks to using this new API as opposed to the good old java.util.Date?

In particular - I am going to be working mainly with JDBC. From what I have seen JDBC handles java.util.Date well. Is it as well suited for LocalDate?

Searching yielded lots of sites telling how to convert from one format to the other, but no definitive answer as to should new code use the old API.

Thanks.


Despite the name, java.util.Date can be used to store both date and time (it stores UTC milliseconds offset since epoch)

I would definitely use the new API because of greater features:

  • Easier format/parsing. The API has its own format/parse methods
  • The API includes addition/subtraction operation (minusMinutes, plusDays, etc)

None of above are available on java.util.Date

Old Date can also be converted into LocalDateTime like this:

    Date oldDate = ...
    LocalDateTime newDateTime = 
      LocalDateTime.from(Instant.ofEpochMilli(oldDate.getTime()));

I’m adding to the correct Answer by Ole V.V.

JDBC 4.2

In particular - I am going to be working mainly with JDBC.

JDBC 4.2 added support for exchanging java.time objects with the database. See the PreparedStatement::setObject and ResultSet::getObject methods.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate today = LocalDate.now( z ) ;
myPreparedStatement.setObject( … , today ) ;

Retrieval.

LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;

For reasons that escape me, the JDBC spec does not require support for the two most commonly used classes: Instant and ZonedDateTime. Your database and JDBC driver may or may not add support for these.

If not, you can easily convert. Start with OffsetDateTime, with support required in JDBC.

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

To see this moment through the wall-clock time used by people of a particular region (a time zone), apply a ZoneId to get a ZonedDateTime object.

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant() ;

To adjust into UTC, extract an Instant. An Instant is always in UTC, by definition.

Instant instant = odt.toInstant() ;

You can convert the other way, to write to a database.

myPreparedStatement.setObject( … , zdt.toOffsetDateTime() ;  // Converting from `ZonedDateTime` to `OffsetDateTime`. Same moment, same point on the timeline, different wall-clock time.

…and:

myPreparedStatement.setObject( … , instant.atOffset( ZoneOffset.UTC ) ) ;  // Converting from `Instant` to `OffsetDateTime`. Same moment, same point on the timeline, and even the same offset. `OffsetDateTime` is a more flexible class with abilities such as (a) applying various offsets and (b) flexible formatting when generating text, while `Instant` is meant to be a more basic building-block class. 

Notice the naming convention used in java.time: at, from, to, with, and so on.

Table of date-time types in Java (both modern and legacy) and in standard SQL.


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.

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

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

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?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

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.


Java 8 and later: no worries

No, there is no reason why you shouldn’t want to use java.time, the modern Java date and time API if you’re on Java 8 or later (where it’s built in).

The only thing one may briefly consider, is the one you have already excluded.

I am writing a new project, which does not need to be backwards compatible.

And even for backward compatibility you can safely use java.time since conversion methods are built into the old classes from Java 8.

Java 6 and 7: weigh

If you’re on Java 6 or 7, you will need to use the ThreeTen-Backport for java.time, further adapted for Android below API level 26 in ThreeTenABP. If you’re doing only very little very simple date and time work and forward compatibility somehow isn’t an issue, you may consider whether the external dependency is worth it. Please take into account that your external dependency is but a backport of what is built into Java 8 and later, so rock solid, and therefore furthermore that you will only need it until you migrate to Java 8 or later. At which time you can change your imports, retest and do away with the backport.

Your examples of thinkable liabilities

Current EE libraries X and Y don't work correctly with LocalDate

There are some examples of that, also library classes in the JDK. My choice would be to use java.time in my own code and only convert just before calling into the API that doesn’t yet accept a java.time type. And conversely if I get an instance of an outdated class from the API, convert it first thing and use java.time for the rest.

This very useful pattern is broken with LocalTime

I know of no such pattern. On the contrary java.time uses patterns immutable objects and factory method, in contrast to most of the old classes.