Convert java.util.Date to what “java.time” type?

20,572

Yes, you definitely should be using the java.time framework whenever possible.

Avoid old date-time classes

The old date-time classes including java.util.Date, java.util.Calendar, and java.text.SimpleDateFormat and such have proven to be poorly designed, confusing, and troublesome. Avoid them where you can. But when you must interoperate with these old types, you can convert between old and new.

Read on for a basic introduction, somewhat over-simplified, to orient you in moving back-and-forth between the old and new date-time classes.

java.time

The java.time framework is defined by JSR 310, inspired by the highly-successful Joda-Time library, and extended by the ThreeTen-Extra project. The bulk of the functionality was back-ported to Java 6 & 7 in the ThreeTen-Backport project, with a further adaptation for Android in the ThreeTenABP project.

What java.time type matches java.util.Date? Well, a java.util.Date object basically represents a moment on the timeline in UTC, a combination of a date and a time-of-day. We can translate that to any of several types in java.time. Each is discussed below. Note that some new methods have been added to the old date-time classes to facilitate conversions.

diagram of converting from java.util.Date/.Calendar through ZonedDateTime (or OffsetDateTime) to the three Local… types

Instant

The building block in java.time is an Instant, a moment on the timeline in UTC with a resolution of nanoseconds.

Generally you should do much of your business logic in UTC. In such work, Instant will be used frequently. Pass around Instant objects, applying a time zone only for presentation to a user. When you do need to apply an offset or time zone, use the types covered further below.

From java.util.Date to Instant

Given that both Instant and java.util.Date are a moment on the timeline in UTC, we can easily move from a java.util.Date to an Instant. The old class has gained a new method, java.util.Date::toInstant.

Instant instant = myUtilDate.toInstant();

You can go the other direction, from an Instant to a java.util.Date. But you may lose information about the fractional second. An Instant tracks nanoseconds, for up to nine digits after the decimal place such as 2016-01-23T12:34:56.123456789Z. Both java.util.Date & .Calendar are limited to milliseconds, for up to three digits after the decimal place such as 2016-01-23T12:34:56.123Z. In this example going from Instant to Date means truncation of the 456789.

java.util.Date myUtilDate = java.util.Date.from(instant);

From java.util.Calendar to Instant

What about a java.util.Calendar instead of a java.util.Date? Internal to the Calendar object, the date-time is tracked as a count of milliseconds from the epoch reference date-time of the first moment of 1970 in UTC (1970-01-01T00:00:00.0Z). So this value can be converted easily to an Instant.

Instant instant = myUtilCalendar.toInstant() ;

From java.util.GregorianCalendar to ZonedDateTime

Even better, if your java.util.Calendar object is actually a java.util.GregorianCalendar you can easily go directly to a ZonedDateTime. This approach has the benefit of retaining the embedded time zone information.

Downcast from the interface of Calendar to the concrete class of GregorianCalendar. Then call the toZonedDateTime and from methods to go back and forth.

if (myUtilCalendar instanceof GregorianCalendar) {
    GregorianCalendar gregCal = (GregorianCalendar) myUtilCalendar; // Downcasting from the interface to the concrete class.
    ZonedDateTime zdt = gregCal.toZonedDateTime();  // Create `ZonedDateTime` with same time zone info found in the `GregorianCalendar`
}

Going the other direction…

java.util.Calendar myUtilCalendar = java.util.GregorianCalendar.from(zdt); // Produces an instant of `GregorianCalendar` which implements `Calendar` interface.

As discussed above, beware that you may be losing information about the fraction of a second. The nanoseconds in the java.time type (ZonedDateTime) gets truncated to milliseconds in the .Calendar/.GregorianCalendar.

OffsetDateTime

From an Instant we can apply an offset-from-UTC to move into a wall-clock time for some locality. An offset is a number of hours, and possibly minutes and seconds, ahead of UTC (eastward) or behind UTC (westward). The ZoneOffset class represents this idea. The result is an OffsetDateTime object.

ZoneOffset offset = ZoneOffset.of("-04:00"); 
OffsetDateTime odt = OffsetDateTime.ofInstant(instant, zoneOffset);

You can go the other direction, from an OffsetDateTime to a java.util.Date. Extract an Instant and then proceed as we saw in code above. As discussed above, any nanoseconds get truncated to milliseconds (data loss).

java.util.Date myUtilDate = java.util.Date.from(odt.toInstant());

ZonedDateTime

Better yet, apply a full time zone. A time zone is an offset plus rules for handling anomalies such as Daylight Saving Time (DST).

Applying a ZoneId gets you a ZonedDateTime object. Use a proper time zone name (continent/region). Never use the 3-4 letter abbreviations commonly seen such as EST or IST as they are neither standardized nor unique.

ZoneId zoneId = ZoneId.of("America/Montreal");
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, zoneId);

You can go the other direction, from an ZonedDateTime to a java.util.Date. Extract an Instant and then proceed as we saw in code above. As discussed above, any nanoseconds get truncated to milliseconds (data loss).

java.util.Date myUtilDate = java.util.Date.from( zdt.toInstant() );

And we saw further above that a ZonedDateTime may be converted to a GregorianCalendar.

LocalDate

Sometimes you may want a date-only value, without time-of-day and without time zone. For that, use a java.time.LocalDate object.

See this Question for more discussion, Convert java.util.Date to java.time.LocalDate, especially this Answer written by the main man behind the invention of both Joda-Time and java.time.

The key is to go through a ZonedDateTime (as generated in code above). We need a time zone to determine a date. The date varies around the world, with a new day dawning earlier in the east. For example, after midnight in Paris is a new day while still “yesterday” in Montréal. So while a LocalDate does not contain a time zone, a time zone is required to determine a LocalDate.

LocalDate localDate = zdt.toLocalDate();

Converting in the other direction from LocalDate to a date-time means inventing a time-of-day. You can choose any time-of-day that makes sense in your business scenario. For most people, the first moment of the day makes sense. You may be tempted to hard code that first moment as the time 00:00:00.0. In some time zones, that time may not be valid as the first moment because of Daylight Saving Time (DST) or other anomalies. So let java.time determine the correct time with a call to atStartOfDay.

ZonedDateTime zdt = localDate.atStartOfDay(zoneId);

LocalTime

On rare occasion you may want only a time-of-day without a date and without a time zone. This concept is represented by the LocalTime class. As discussed above with LocalDate, we need a time zone to determine a LocalTime even though the LocalTime object does not contain (does not ‘remember’) that time zone. So, again, we go through a ZonedDateTime object obtained from an Instant as seen above.

LocalTime localTime = zdt.toLocalTime();

LocalDateTime

As with the other two Local… types, a LocalDateTime has no time zone nor offset assigned. As such you may rarely use this. It gives you a rough idea of a date-time but is not a point on the timeline. Use this if you mean some general date and some time that might be applied to a time zone.

For example, “Christmas starts this year” would be 2016-12-25T00:00:00.0. Note the lack of any offset or time zone in that textual representation of a LocalDateTime. Christmas starts sooner in Delhi India than it does in Paris France, and later still in Montréal Québec Canada. Applying each of those areas’ time zone would yield a different moment on the timeline.

LocalDateTime ldt = zdt.toLocalDateTime();

enter image description here


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?

Share:
20,572

Related videos on Youtube

Basil Bourque
Author by

Basil Bourque

SOreadytohelp

Updated on July 09, 2022

Comments

  • Basil Bourque
    Basil Bourque almost 2 years

    I have a java.util.Date object, or a java.util.Calendar object. How do I convert that to the right type in java.time framework?

    I have heard that we should now be doing the bulk of our business logic with java.time types. When working with old code not yet updated for java.time I need to be able to convert back and forth. What types map to java.util.Date or java.util.Calendar?

    • aviad
      aviad about 8 years
      Thanks for asking (and for answering)! Why not to use JodaTime BTW?
    • Kayaman
      Kayaman about 8 years
      @aviad JodaTime was necessary before Java 8's new Time API (which was influenced a lot by JodaTime I believe, maybe even by the same people). It's not that useful anymore.
    • Basil Bourque
      Basil Bourque about 7 years
      @aviad The java.time framework is the official replacement for Joda-Time. Both projects are led by the same man, Stephen Colebourne (“jodastephen”).
  • Jon Skeet
    Jon Skeet about 8 years
    An instant in time isn't "a combination of a date and a time-of-day" - because that assumes a particular calendar system (and time zone). I agree that Date maps to Instant, but I think Calendar more accurately maps to ZonedDateTime (if you're happy to assume a Gregorian calendar) or ChronoZonedDateTime if you want to support arbitrary calendar systems.
  • Jim Garrison
    Jim Garrison about 8 years
    Rather than reposting your prior answer you should probably flag this question as a duplicate of the one for which you originally posted this answer. See meta.stackoverflow.com/questions/292329
  • Basil Bourque
    Basil Bourque about 8 years
    @JonSkeet I totally agree, but my idea here was to cover the basics, just to get people oriented to the new types. I searched and realized we have various this-to-that conversion questions, but not a general introductory question-answer. I'll add a disclaimer up top.
  • Basil Bourque
    Basil Bourque about 8 years
    @JimGarrison I just wrote this answer (and diagram) from scratch right now. If you can point me to a duplicate, please do.
  • Jim Garrison
    Jim Garrison about 8 years
    This answer looks like an expanded version of stackoverflow.com/a/35924696/18157
  • Basil Bourque
    Basil Bourque about 8 years
    @JimGarrison You pointed to a question and answer that was all about generating strings formatted to the ISO 8601 standard. I did not even mention generating strings, formatting, or ISO 8601 at all here (purposely). Nor did I touch on the java.sql types here as I did there (purposely). I will grant you, much of this material has been written by me and others in various pieces in various places. But at the moment I was inspired to write a general overview to how to convert back-and-forth between the old types and java.time.
  • chrisl08
    chrisl08 about 8 years
    Maybe I am old school, but where do you base this statement: "The old date-time classes including java.util.Date, java.util.Calendar, and java.text.SimpleTextFormat and such have proven to be poorly designed, confusing, and troublesome. " I have written more than my fair share of java applications and good old java.util.date and java.sql.date where never "poorly designed, confusing, and troublesome", at least to me.
  • chrisl08
    chrisl08 about 8 years
    In addition, IMHO statements like 'You should use this instead of that' and 'the existing classes are poorly designed, confusing, and troublesome' should be backed up with proper proof before made on StackOverflow.
  • Jon Skeet
    Jon Skeet about 8 years
    @chrisl08: No, they really really are. They're awful APIs. Just look at how much of java.util.Date is deprecated. Just look at how many users on Stack Overflow are confused by Date.toString() showing the value in the system local time zone, and inferring that Date has information about a time zone. Just look at the inheritance relationship between java.sql.Date and java.util.Date, where java.sql.Date is meant to just represent a date, but doesn't even specify what time zone that's supposedly in, when java.util.Date is a point in time. I could rant for hours about this...
  • Jon Skeet
    Jon Skeet about 8 years
    @chrisl08: You could start with stackoverflow.com/questions/1969442/…
  • Basil Bourque
    Basil Bourque about 8 years
    @chrisl08 Any quick search an Stack Overflow will lead you to a nearly endless flow of confusion and pain caused by those old date-time classes. Their many flaws have been explained many times in many places. Not even debatable at this point in history -- certainly let us not get into it here. While those old classes were a brave first attempt (by Taligent and IBM) in an industry that had for too long ignored this difficult but crucial topic of date-time handling, in the end they were nowhere near good enough. Thus Joda-Time, and now its successor, java.time.
  • assylias
    assylias about 8 years
    @BasilBourque Instant instant = Instant.ofEpochMilli( myUtilCalendar.time() ); ==> Instant instant = myUtilCalendar.toInstant();
  • JodaStephen
    JodaStephen about 8 years
    Good question and answer. Worth noting the new method on Calendar: toInstant(): docs.oracle.com/javase/8/docs/api/java/util/… . GregorianCalendar has two new methods: toZonedDateTime() and from(ZonedDateTime)
  • Basil Bourque
    Basil Bourque about 8 years
    @JodaStephen & assylias - Thanks for comments about .Calendar. Incorporated into text and diagram.
  • Basil Bourque
    Basil Bourque almost 5 years
    @MCEmperor Thanks for trying to make improvements, but the SPACE characters in my code samples are intentional. We have wide-format screens, Retina hi-res displays, so we need not keep coding with the conventions of a computer terminal screen with 72 columns. Wecanaffordafewspacestomakecodemorereadable.