Whats the difference between java.util.Date and Zo

2019-08-28 10:08发布

问题:

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..

回答1:

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.

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 ) ; 


回答2:

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



回答3:

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.