Zhenya
Zhenya

Reputation: 6198

What's the difference between ZonedDateTime and OffsetDateTime?

I've read the documentation, but I still can't get when I should use one or the other:

According to documentation OffsetDateTime should be used when writing date to database, but I don't get why.

Upvotes: 217

Views: 81413

Answers (4)

Basil Bourque
Basil Bourque

Reputation: 338785

Moment

You have three ways to represent a moment, a specific point on the timeline.

Concept Java SQL standard
A moment as seen with an offset from UTC of zero hours-minutes-seconds Instant
A moment as seen with an offset from UTC of some number of hours-minutes-seconds OffsetDateTime TIMESTAMP WITH TIME ZONE
A moment as seen through the wall-clock/calendar used by the people of a particular region ZonedDateTime
Instant instant = Instant.now() ;               // .toString() -> 2024-07-07T18:28:15.268003Z  (the `Z` is short for `+00:00`, offset of zero)

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;    // .toString() -> Pacific/Auckland
ZonedDateTime zdt = instant.atZone( z ) ;       // .toString() -> 2024-07-08T06:28:15.268003+12:00[Pacific/Auckland]

OffsetDateTime odt = zdt.toOffsetDateTime() ;   // .toString() -> 2024-07-08T06:28:15.268003+12:00

See that code run at Ideone.com.

Offset versus Time zone

  • Offset
    An offset is merely a number of hours-minutes-seconds ahead or behind the temporal meridian of UTC.
  • Time Zone
    A time zone is much more. A time zone is a named history of the past, present, and future changes to the offset used by the people of a particular region as decided by their politicians.

Time zone names use the format of Continent/Region such as Europe/Paris and Africa/Casablanca.

Example:

  • +08:00 is an offset. This means "eight hours ahead of UTC".
  • Asia/Kuala_Lumpur is the name of a time zone. At the time of this writing, that time zone is using an offset of +08:00.

Instant

The java.time.Instant class represents a moment as seen through an offset from UTC of zero hours-minutes-seconds.

OffsetDateTime

The class java.time.OffsetDateTime represents a moment, a point on the timeline, as seen through a particular offset.

SQL database

Importantly, the SQL standard defines a moment only by way of an offset. So OffsetDateTime is the only way to exchange a moment with a database via SQL and JDBC.

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

… and:

myPreparedStatement.setObject( … , odt ) ;

ZonedDateTime

The class java.time.ZonedDateTime represent a moment as seen through the wall-clock/calendar used by the people of a particular region. The offset used by those people may change over time for various reasons (observance of Daylight Saving Time, war & occupation, diplomacy, internal politics, etc.).

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;

If doing date-time math, adding or subtracting a span of time to move forward into the future or backward into the past, use ZonedDateTime rather than OffsetDateTime. Because the politicians controlling a time may choose to alter their offset, you must use ZonedDateTime to account those changes in offset. And you must be using an up-to-date tzdata file.


Summary…

In most business app scenarios, you will be using Instant in business logic except where business rules necessitate the context of a time zone in which case you use ZonedDateTime. And you would use ZonedDateTime for presentation to the user where they expect so. Rarely would you use OffsetDateTime.

The OffsetDateTime class is generally unused, with the big exception of exchanging a moment with databases. When a database is involved, you will likely find yourself converting back and forth between OffsetDateTime and Instant/ZonedDateTime.

Upvotes: 4

Mohsin AR
Mohsin AR

Reputation: 3108

Apart from programming, I am giving you an example to understand ZonedDateTime and OffsetDateTime in the real world. ZonedDateTime: let's say I am in Pakistan now and right now the data and time is 2024-03-07T13:05:00.00000 (13:05 == 01:05 pm), if I add +03:00 the time would be the current time in Thailand (15:05 == 03:05 pm), OffsetDateTime: OffsetDateTime: start by UTC+00:00 and the current time is 2024-03-07T08:05:00.00000 (08:05 am), if I add +03:00 the time would be current time in Saudi Arabia (11:05 am).

So OffsetDateTime starts from UTC+00:00 and ZonedDateTime starts from your current zone time. please refer attached wiki link

Upvotes: 1

Sam YC
Sam YC

Reputation: 11617

The accepted answer give very completed explanation, perhaps below code example can provide you short and clear picture:

Instant instant = Instant.now();
Clock clock = Clock.fixed(instant, ZoneId.of("America/New_York"));
OffsetDateTime offsetDateTime = OffsetDateTime.now(clock);
ZonedDateTime zonedDateTime = ZonedDateTime.now(clock);

System.out.println(offsetDateTime); // 2019-01-03T19:10:16.806-05:00
System.out.println(zonedDateTime);  // 2019-01-03T19:10:16.806-05:00[America/New_York]
System.out.println();

OffsetDateTime offsetPlusSixMonths = offsetDateTime.plusMonths(6);
ZonedDateTime zonedDateTimePlusSixMonths = zonedDateTime.plusMonths(6);

System.out.println(offsetPlusSixMonths); // 2019-07-03T19:10:16.806-05:00
System.out.println(zonedDateTimePlusSixMonths); // 2019-07-03T19:10:16.806-04:00[America/New_York]
System.out.println(zonedDateTimePlusSixMonths.toEpochSecond() - offsetPlusSixMonths.toEpochSecond()); // -3600

System.out.println();
System.out.println(zonedDateTimePlusSixMonths.toLocalDateTime()); // 2019-07-03T19:10:16.806
System.out.println(offsetPlusSixMonths.toLocalDateTime()); // 2019-07-03T19:10:16.806

In short, use ZonedDateTime only if you want to factor in Daylight saving, typically there will be one hour difference, as you can see the example above, the offset of ZonedDateTime change from -5:00 to -04:00, in most case, your business logic might end up with bug.

(code copy from https://www.youtube.com/watch?v=nEQhx9hGutQ)

Upvotes: 35

Stephen C
Stephen C

Reputation: 718926

Q: What's the difference between java 8 ZonedDateTime and OffsetDateTime?

The javadocs say this:

"OffsetDateTime, ZonedDateTime and Instant all store an instant on the time-line to nanosecond precision. Instant is the simplest, simply representing the instant. OffsetDateTime adds to the instant the offset from UTC/Greenwich, which allows the local date-time to be obtained. ZonedDateTime adds full time-zone rules."

Source: https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html

Thus the difference between OffsetDateTime and ZonedDateTime is that the latter includes the rules that cover daylight saving time adjustments and various other anomalies.

Stated simply:

Time Zone = ( Offset-From-UTC + Rules-For-Anomalies )


Q: According to documentation OffsetDateTime should be used when writing date to database, but I don't get why.

Dates with local time offsets always represent the same instants in time, and therefore have a stable ordering. By contrast, the meaning of dates with full timezone information is unstable in the face of adjustments to the rules for the respective timezones. (And these do happen; e.g. for date-time values in the future.) So if you store and then retrieve a ZonedDateTime the implementation has a problem:

  • It can store the computed offset ... and the retrieved object may then have an offset that is inconsistent with the current rules for the zone-id.

  • It can discard the computed offset ... and the retrieved object then represents a different point in the absolute / universal timeline than the one that was stored.

If you use Java object serialization, the Java 9 implementation takes the first approach. This is arguably the "more correct" way to handle this, but this doesn't appear to be documented. (JDBC drivers and ORM bindings are presumably making similar decisions, and are hopefully getting it right.)

But if you are writing an application that manually stores date/time values, or that rely on java.sql.DateTime, then dealing with the complications of a zone-id is ... probably something to be avoided. Hence the advice.

Note that dates whose meaning / ordering is unstable over time may be problematic for an application. And since changes to zone rules are an edge case, the problems are liable to emerge at unexpected times.


A (possible) second reason for the advice is that the construction of a ZonedDateTime is ambiguous at the certain points. For example in the period in time when you are "putting the clocks back", combining a local time and a zone-id can give you two different offsets. The ZonedDateTime will consistently pick one over the other ... but this isn't always the correct choice.

Now, this could be a problem for any applications that construct ZonedDateTime values that way. But from the perspective of someone building an enterprise application is a bigger problem when the (possibly incorrect) ZonedDateTime values are persistent and used later.

Upvotes: 266

Related Questions