开发者

Difference between Date class in Package java.util & Package java.sql

In java, both the java.util and the java.sql package contain a Date class, So what is the difference betw开发者_运维技巧een them?

If one Date class is present in Java then what is the need of another Date class?


From the JavaDoc of java.sql.Date:

A thin wrapper around a millisecond value that allows JDBC to identify this as an SQL DATE value. A milliseconds value represents the number of milliseconds that have passed since January 1, 1970 00:00:00.000 GMT.

To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.

Explanation: A java.util.Date represents date and time of day, a java.sql.Date only represents a date (the complement of java.sql.Date is java.sql.Time, which only represents a time of day, but also extends java.util.Date).


These answers seem to be partially outdated.

I just read a little API Code (Java Version 1.8.0_91) and found this in java.sql.Date:

/**
 * Creates a date which corresponds to the day determined by the supplied
 * milliseconds time value {@code theDate}.
 *
 * @param theDate
 *            a time value in milliseconds since the epoch - January 1 1970
 *            00:00:00 GMT. The time value (hours, minutes, seconds,
 *            milliseconds) stored in the {@code Date} object is adjusted to
 *            correspond to 00:00:00 GMT on the day determined by the supplied
 *            time value.
 */
public Date(long theDate) {
    super(normalizeTime(theDate));
}

/*
 * Private method which normalizes a Time value, removing all low
 * significance digits corresponding to milliseconds, seconds, minutes and
 * hours, so that the returned Time value corresponds to 00:00:00 GMT on a
 * particular day.
 */
private static long normalizeTime(long theTime) {
    return theTime;
}

The method for normalizing the time is still there and even the comment says that the time will be normalized to 00:00:00 GMT but it does nothing. For some reason they removed the normalization, wich means, that a java.sql.Date contains just like a java.util.Date just the number of milliseconds since 1.1.1970. So there is a time component but it is not displayed externally.

For example the code

java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(Calendar.getInstance().getTimeInMillis())

System.out.println(utilDate);
System.out.println(sqlDate);

produces the output

Thu Jun 02 13:17:35 CEST 2016
2016-06-02

So be careful with sql dates and do not handle them like they would just contain a Date and no time information. For example:

java.sql.Date sqlDate1 = new java.sql.Date(Calendar.getInstance().getTimeInMillis());
java.sql.Date sqlDate2 = new java.sql.Date(Calendar.getInstance().getTimeInMillis());

System.out.println(sqlDate1);
System.out.println(sqlDate2);
System.out.println(sqlDate1.equals(sqlDate2));
System.out.println(sqlDate1.toString().equals(sqlDate2.toString()));

prints:

2016-06-02
2016-06-02
false
true


Java.util.Date is the generic all-purpose Date object. It stores a Date (as a long) and allows you to display it.

java.sql.Date extends java.util.Date. Main difference to note is that java.sql.Date does not have a time component.


The Old

java.util.Date

The java.util.Date class is part of the old date-time classes that have proven to be poorly designed, confusing, and troublesome. The intent is to represent a moment (a date and a time-of-day) on the timeline.

The class seems to represent a moment in UTC, except that its toString method silently applies the JVM’s current default time zone while generating the String which creates the illusion that a java.util.Date has a time zone but actually does not. Well, actually it does have a time zone assigned deep in its source code used for somethings internally but not obvious and not settable nor gettable. A confusing mess.

java.sql.Date

The java.sql.Date makes a bad situation worse by representing the a date-only value (as is meant by “DATE” in the SQL database world) but did so as a hack by extending java.util.Date. But the you are supposed to pretend it is not a subclass, as directed in the class doc. Furthermore, it has time-of-day but pretends not to by adjusting to first moment of the day in UTC. A confusing mess.

And one more thing… the java.sql.Date class adds on a fractional second with a resolution of nanoseconds. That goes beyond the milliseconds resolution used by java.util.Date. Many databases support finer resolutions such as microsecond or nanosecond.

So in these old date-time classes there is no way to truly represent a date-only value with no time-of-day nor time zone.

The New

The java.time framework comes to the rescue. Inspired by the highly successful Joda-Time project. Built into Java 8 and later. Back-ported to Java 6 & 7, and further adapted to Android. See Oracle Tutorial.

Instant

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds. Clear and simple.

Instant instant = Instant.now();

instant.toString() → 2016-06-19T02:34:55.564Z

If a java.util.Date is needed for use with old code, you can convert. See new methods added to the old class: java.util.Date::toInstant() and java.util.Date.from( Instant ).

Zoned

To adjust into some locality’s wall-clock time, apply an offset-from-UTC (ZoneOffset) to get a OffsetDateTime object. Even better, if you know the proper time zone name, apply a ZoneId to get a ZonedDateTime.

For example America/Montreal is four hours behind UTC in summer under Daylight Saving Time (DST), so we see 10 PM (22:00) on the previous date in code below rather than 2 AM in the example above. Going back four hours crossed over midnight into the previous date. But both the instant object seen above and the zdt object seen next both represent the same simultaneous moment on the timeline. Same moment in history but is “tomorrow” in Paris, Kolkata, and Auckland while “yesterday” in Montréal, Mexico City, and Honolulu.

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

zdt.toString() → 2016-06-18T22:34:55.564-04:00[America/Montreal]

LocalDate

For a date-only value, use the LocalDate class. No time-of-day nor time zone is retained.

LocalDate localDate = zdt.toLocalDate();

But note that a time zone is crucial in determining a date as for any given moment the date can vary around the globe by time zone. Thus the discussion above about specifying a time zone. For example, see next how we get the 18th of June rather than the 19th.

localDate.toString() → 2016-06-18

If this distinction between dates by time zone is significant to your business, you should be using a date-time value stored in a database column type of TIMESTAMP WITH TIME ZONE rather than DATE.

Search Stack Overflow for much more information and many examples of java.time (tag: java-time).

Database

So save to a database, use a JDBC driver complying with JDBC 4.2 spec (see Guide). Call setObject and getObject on PreparedStatement to directly use the java.time objects.

If your JDBC driver does not yet support such direct use of the java.time types, use the new methods added to the old classes to facilitate conversion. But minimize your use of the old classes; convert into java.time immediately and use only java.time objects in your business logic.

java.sql.Date mySqlDate = java.sql.Date.valueOf( localDate );

And the other direction.

LocalDate localDate = mySqlDate.toLocalDate();


java.sql.Date accepts a long integer which represents the amount of milliseconds since January 1, 1970. If the given number is negative it refers time before January 1, 1970. Remember, the encapsulated value inside the object represents only date like January 1, 1970 and no time information is stored.

java.util.Date stores both date as well as time information. It is more commonly used than java.sql.Date.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜