1. Overview

ZonedDateTime and OffsetDateTime are pretty popular classes in the Java 8 DateTime API. Furthermore, both store an instant on the timeline up to a precision of nanoseconds.** And, at first, it may get confusing to choose between them.

In this quick tutorial, we’re going to look at the differences between ZonedDateTime and OffsetDateTime.

2. ZonedDateTime

A ZonedDateTime is an immutable representation of a date-time with a timezone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00 Europe/Paris. It holds state equivalent to three separate objects: a LocalDateTime, a ZoneId, and the resolved ZoneOffset.

Here, the ZoneId determines how and when the offset changes. So, the offset can’t be freely set, as the zone controls which offsets are valid.

To get the current ZonedDateTime for a specific region, we’ll use:

ZoneId zone = ZoneId.of("Europe/Berlin");
ZonedDateTime zonedDateTime = ZonedDateTime.now(zone);

The ZonedDateTime class also provides built-in methods for converting a given date from one timezone to another:

ZonedDateTime destZonedDateTime = sourceZonedDateTime.withZoneSameInstant(destZoneId);

Finally, it’s fully DST-aware and handles daylight saving time adjustments. It often comes in handy when we want to display a date-time field in a specific timezone.

3. OffsetDateTime

An OffsetDateTime is an immutable representation of a date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00. In other words, it stores all date and time fields, to a precision of nanoseconds, as well as the offset from GMT/UTC.

Let’s get the current OffsetDateTime with a two-hour offset from GMT/UTC:

ZoneOffset zoneOffSet= ZoneOffset.of("+02:00");
OffsetDateTime offsetDateTime = OffsetDateTime.now(zoneOffSet);

4. The Main Differences

First, it doesn’t make sense (without conversions) to directly compare two dates with full timezone information. Therefore, we should always prefer storing OffsetDateTime in the database over the ZonedDateTime, as dates with a local time offset always represent the same instants in time.

Moreover, unlike with the ZonedDateTime, adding an index over a column storing the OffsetDateTime won’t change the meaning of the date.

Let’s quickly sum up the key differences.

ZonedDateTime:

  • stores all date and time fields, to a precision of nanoseconds, and a timezone, with a zone offset used to handle ambiguous local date-times
  • can’t freely set offsets, as the zone controls the valid offset values
  • is fully DST-aware and handles daylight savings adjustments
  • comes in handy for displaying date-time fields in a user-specific timezone

OffsetDateTime**:**

  • stores all date and time fields, to a precision of nanoseconds, as well as the offset from GMT/UTC (no timezone information)
  • should be used for storing a date in the database or communicating it over a network

5. Conclusion

In this tutorial, we covered the differences between the ZonedDateTime and the OffsetDateTime.

As usual, the complete source code is available over on Github.