7

While using util.date and giving date with time to service from browser and then saving to db and taking it back it gives different date time against setting zoneddatetime directly from service.

Any help would be appreciated..

Derrick
  • 3,669
  • 5
  • 35
  • 50
Vivek Kumar
  • 360
  • 1
  • 7
  • 16
  • 1
    Possible duplicate of [Should I use java.util.Date or switch to java.time.LocalDate](https://stackoverflow.com/questions/28730136/should-i-use-java-util-date-or-switch-to-java-time-localdate) – Michael Feb 27 '19 at 19:09
  • 1
    @Michael Not really a duplicate. A `LocalDate` object represents a date-only, without a time-of-day and without a time zone. In contrast, both `Date` and `ZonedDateTime` listed here represent a moment, not a date-only. – Basil Bourque Feb 27 '19 at 19:17
  • @BasilBourque There are practically infinite combinations of questions of the form "what is the difference between class X and class Y". What is the difference between String and InputStream? What is the difference between Integer and ExpressionFieldProxyEventBroadcaster? The core of this question is summed up there: "which datetime library should I use?" – Michael Feb 27 '19 at 19:23
  • @Michael I understand your point about infinite combinations. But I disagree in this particular case. There is a couple vital core concepts at play here (moment vs date-only, and UTC vs time zone). Matters are further complicated by the tragically poor naming of `Date` which does not fact handle a date, it handles a moment. So this seems a worthwhile Question as written. However, there may well be another original of which this question is a duplicate. – Basil Bourque Feb 27 '19 at 19:29
  • 1
    @BasilBourque My point is that it shouldn't matter if there is an exact literal match. If that was the criteria, we would end up with: What is the difference between Date and LocalDate? What is the difference between Date and LocalDateTime? What is the difference between Date and Instant? What is the difference between Date and LocalTime? You get the point. By pandering to this kind of lazy question, you are not making good information *more* easy to find, you are only making it more fractured. – Michael Feb 27 '19 at 19:33
  • 1
    I don’t understand your setup, nor what you are trying to do. A [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve), please? The answers are correct, you should avoid the `Date` class and friends and use java.time, the modern date and time API. – Ole V.V. Feb 28 '19 at 05:08

3 Answers3

36

tl;dr

Whats the difference between java.util.Date and Zoneddatetime?

  • Date represents a moment in UTC, while ZonedDateTime represents a moment in a particular time zone.
  • Date is a terrible class, riddled with design flaws, that should never be used, while ZonedDateTime is a modern class from the java.time package that you will find quite useful.

Java comes with two very different frameworks for handling date-time work: a terribly awkward and failed set of legacy classes, and an modern industry-leading set of classes found in the java.time package.

Legacy ➙ modern:

  • java.util.Date was replaced by java.time.Instant
    • Both represent a moment in UTC.
  • java.util.GregorianCalendar was replaced by java.time.ZonedDateTime
    • Both represent a moment as seen in a particular time zone.

table of legacy and modern classes for date-time handling in Java

java.util.Date

The Date class represents a moment in UTC. That is, a date, a time-of-day, plus the context of UTC.

Internally, it is a count of milliseconds since the epoch reference date of first moment of 1970 in UTC, 1970-01-01T00:00:00Z.

To complicate matters:

  • There is a time zone capture upon creation, stored deep inside, without getters or setters. So for the most part we can ignore this zone, though it does apply for matters such has this class’ implementation of equals.
  • When calling toString this class has the very confusing behavior of dynamically applying the JVM’s current time zone while generating text to represent the value of this object. While well-intentioned, this anti-feature has caused incalculable pain among Java programmers trying to learn date-time handling.

Confused? Yes, this class is confusing, a wretched mess of poor design decisions. Compounded by the later addition of java.util.Calendar & GregorianCalendar.

All of these troublesome date-time classes bundled with the earliest version of Java are now supplanted entirely by the java.time classes.

In particular, java.util.Date is replaced by java.time.Instant. Both represent a moment in UTC as count from the epoch of 1970 UTC. But Instant carries a finer resolution, nanoseconds rather than milliseconds.

You can convert back-and-forth between the legacy class Date and the modern class Instant by calling new methods added to the old class. Usually, you will avoid ever using Date. But when interfacing with old code not yet updated to java.time, you may need to convert.

java.time.ZonedDateTime

The modern class ZonedDateTime represent a moment as seen in the wall-clock time used by the people of a certain region (a time zone).

So Instant and ZonedDateTime are similar in that they both represent a moment, a specific point on that timeline. The difference is that ZonedDateTime knows about the rules of a time zone. So a ZonedDateTime knows how to account for anomalies such as Daylight Saving Time (DST) or other changes to time-keeping required by politicians.

You can think of it as:

ZonedDateTime = ( Instant + ZoneId )

We can easily adjust from UTC to some time zone by applying a time zone (ZoneId) to a Instant object.

Instant instant = Instant.now() ;             // Capture the current moment as seen in UTC.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;     // Apply a time zone to see the same moment through the wall-clock time in use by the people of a particular region (a time zone). 

See this code run live at IdeOne.com. Note the different date and the different time-of-day, yet the same simultaneous moment.

instant.toString(): 2019-02-27T19:32:43.366Z

zdt.toString(): 2019-02-28T04:32:43.366+09:00[Asia/Tokyo]

Crucial concept: Instant and ZonedDateTime both represent the same moment, the same simultaneous point on the timeline. They differ in the wall-clock time. For example, if someone in Japan calls someone in Iceland (where UTC is used for their clocks all the time), and they both look up at the clock hanging on their respective walls, they will see a different time-of-day and possibly even a different date on the monthly calendar. Same moment, different wall-clock time.

As for the legacy classes, the equivalent of ZonedDateTime is GregorianCalendar, a concrete implementation of java.util.Calendar. Indeed, the old class GregorianCalendar gained new methods for conversion to/from ZonedDateTime.

ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime();  // Convert from legacy to modern class.

…and…

GregorianCalendar gc = GregorianCalendar.from( zdt ) ;      // Convert from modern to legacy class.

Conclusion

So a Date is equivalent to a Instant, both being a moment in UTC. But a ZonedDateTime differs from both in that a time zone has adjusted the perception of the moment by applying the lens of a region’s people’s wall-clock time adjustment.

Tips:

  • Never use Date. When handed a Date, immediately convert to Instant. Then proceed with your business logic.
  • Do most of your work in UTC. Tracking moments, debugging, logging, exchanging date-time values, and persisting to database should generally be done in UTC. Learn to forget about your own parochial time zone when on the job as a programmer. Keep a second clock on your desk set to UTC.

Database

The Question mentions database work. Here is a quick summary. Search Stack Overflow for more detail as this has been handled many times already.

As of JDBC 4.2, we can directly exchange java.time objects with the database. Use PreparedStatement::setObject and ResultSet::getObject. No need to ever again touch the terrible java.sql.* classes such as java.sql.Timestamp.

You may be able to exchange an Instant but the JDBC spec does not require that. The spec instead requires OffsetDateTime.

Retrieval.

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

And storage.

myPreparedStatement.setObject( … , odt ) ;

If you have an Instant in hand, convert to OffsetDateTime using the constant ZoneOffset.UTC.

OffsetDateTime odt = Instant.atOffset( ZoneOffset.UTC ) ;

To view that moment through the wall-clock time of some region, apply a ZoneId.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

To store a ZonedDateTime to the database, convert to OffsetDateTime. This strips off the time zone information (the history of past, present, and future changes made to the offset used by the people of this region as decided by their politicians), leaving the date, the time-of-day, and the offset-from-UTC (a number of hours-minutes-seconds).

OffsetDateTime odt = zdt.toOffsetDateTime(); 

Most databases store a moment in UTC for a column of the SQL-standard type TIMESTAMP WITH TIMESTAMP. When submitting your OffsetDateTime to the database, your JDBC driver is likely to adjust the offset in the OffsetDateTime to zero hours-minutes-seconds (to UTC itself). But I like do so explicitly. It makes debugging easier, and it demonstrates to the reader my understanding of the moment being stored in UTC.

OffsetDateTime odt = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC ) ; 

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

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Thank you for that explonation. I can't understand one thing. Why we should convert `ZoneDateTime` to `OffsetDateTime` when storing in database? We can easily store it as `Instant + Offset` so we can map it to SQL `TIMESTAMP WITH TIME ZONE` type. – Martin Mar 31 '20 at 19:11
  • 1
    @Martin The [JDBC 4.2](https://www.jcp.org/en/jsr/detail?id=221) spec requires support for `OffsetDateTime` but, oddly enough, does *not* require support for the two more commonly used types: `Instant` & `ZonedDateTime`. Your JDBC driver may or may not support the other two classes. If so, you can use those types. If you want to write more portable code, stick with `OffsetDateTime`. I will add a graphic table to this Answer with pink stripes showing the types required by JDBC 4.2. – Basil Bourque Mar 31 '20 at 19:22
  • Excellent post. Minor nitpick: In my opinion it shouldn't say `TIMESTAMP WITH TIME ZONE` next to `OffsetDateTime` and `ZonedDateTime` because it reinforces the misconception that `TIMESTAMP WITH TIME ZONE` *stored* a time zone. In SQL `TIMESTAMP WITH TIME ZONE` only means that time zone conversion *can* be performed on such a column, it does not actually hold any particular time zone. – AndreKR Oct 07 '21 at 18:31
  • @AndreKR Good point. I will keep that in mind when I revise the graphic. – Basil Bourque Oct 07 '21 at 18:34
  • 1
    @Basil Bourque, thank you very much for this detailed and well written summary of handling dates in the Java world. I'm using a server response with a Date object which I don't control. Especially the toString() value of Date object was making things very complicated. I now have a good set of ground rules. Convert to instant and never touch again :) – Rvb84 Nov 28 '21 at 13:31
1

java.util.Date is an almost deprecated class which provide a wrapper around millisecond value. It does not provide any information about the time zone, hasn't any helpful methods and you should always avoid using it.

ZonedDateTime is a class from new JDK8 date API which provides a date-time with a time-zone in the ISO-8601 calendar system. You should check

Oracle's explanation for new date format

ByeBye
  • 6,650
  • 5
  • 30
  • 63
1

Sixteen years ago, I wrote an article for JavaWorld magazine entitled What's Your Time Zone which dealt with the issue you describe when using class java.util.Date. In order to "see" the value of an instance of class java.util.Date, you have to convert it to a String. Before java 1.8, this conversion always took the time zone into consideration as well. That's one of the reasons why, in Java 1.8, a new Date-Time API was introduced. New code that's written for Java versions 1.8 and above, should use the new API. I believe you should also consider converting old code to use the new API, if possible.

Abra
  • 19,142
  • 7
  • 29
  • 41