views:

791

answers:

4

java.util.Date vs java.sql.Date: when to use which and why?

+2  A: 

The only time to use java.sql.Date is in a PreparedStatement.setDate. Otherwise, use java.util.Date. It's telling that ResultSet.getDate returns a java.sql.Date but it can be assigned directly to a java.util.Date.

Paul Tomblin
Ehm, ResultSet#getDate() returns sql.Date (which extends util.Date).
Esko
@Esko - "Ehm", I fixed that before you commented (and downvoted).
Paul Tomblin
@Paul: Well maybe that's some caching issue then because I didn't see your edit earlier. You still have a certain semantic issue in your answer though which I go through in my answer so the downvote stands.
Esko
A: 

It's a wrapper around java.util.Date to handle SQL dates (the 2010-01-01 format).

String sqldate = java.sql.Date(millisecsTimestamp).toString();
matiasf
It has nothing to do with the print format, it's just that they round the time to the beginning of the day (hours, minutes, seconds and milliseconds are all zero).
Paul Tomblin
Yes, but you can't send an object to your SQL server, at some point you will have to convert it to a string. Look at the *.sql.Date().toString() and *.util.Date().toString() methods respectively.
matiasf
Why do you assume that SQL server needs a date as string ? Having a toString method doesn't mean nothing.
Lluis Martinez
+11  A: 

Congratulations, you've hit my favorite pet peeve with JDBC: Date class handling.

Basically databases usually support at least three forms of datetime fields which are date, time and timestamp. Each of these have a corresponding class in JDBC and each of them extend java.util.Date. Quick semantics of each of these three are the following:

  • java.sql.Date corresponds to SQL DATE which means it stores years, months and days while hour, minute, second and millisecond are ignored. Additionally sql.Date isn't tied to timezones.
  • java.sql.Time corresponds to SQL TIME and as should be obvious, only contains information about hour, minutes, seconds and milliseconds.
  • java.sql.Timestamp corresponds to SQL TIMESTAMP which is exact date to the nanosecond (note that util.Date only supports milliseconds!) with customizable precision.

One of the commonest bugs in JDBC drivers in relation to these three types is that the types are handled incorrectly. This means that sql.Date is timezone specific, sql.Time contains current year, month and day et cetera et cetera.

Finally: Which one to use?

Depends on the SQL type of the field, really. PreparedStatement has setters for all three values, #setDate() being the one for sql.Date, #setTime() for sql.Time and #setTimestamp() for sql.Timestamp.

Do note that if you use ps.setObject(fieldIndex, utilDateObject); you can actually give a normal util.Date to most JDBC drivers which will happily devour it as if it was of the correct type but when you request the data afterwards, you may notice that you're actually missing stuff.

I'm really saying that none of the Dates should be used at all.

What I am saying that save the milliseconds/nanoseconds as plain longs and convert them to whatever objects you are using (obligatory joda-time plug). One hacky way which can be done is to store the date component as one long and time component as another, for example right now would be 20100221 and 154536123. These magic numbers can be used in SQL queries and will be portable from database to another and will let you avoid this part of JDBC/Java Date API:s entirely.

Esko
Nice answer. But isn't storing dates as longs a bit unfriendly for the DBA?
cherouvim
Perhaps, however DBA:s generally tend to their RDBMS of choice and rejecting everything that isn't about that RDBMS directly (*I'm looking at you, Oracle fans*) while Java applications are expected to work with all of them. Personally I don't like to put my logic into DB at all.
Esko
A: 

java.sql.Date - when you call methods/constructors of libraries that use it (like JDBC). Not otherwise. You don't want to introduce dependencies to the database libraries for applications/modules that don't explicitly deal with JDBC.

java.util.Date - when using libraries that use it. Otherwise, as little as possible, for several reasons:

  • It's mutable, which means you have to make a defensive copy of it every time you pass it to or return it from a method.

  • It doesn't handle dates very well, which backwards people like yours truly, think date handling classes should.

  • Now, because j.u.D doesn't do it's job very well, the ghastly Calendar classes were introduced. They are also mutable, and awful to work with, and should be avoided if you don't have any choice.

  • There are better alternatives, like the Joda Time API (which might even make it into Java 7 and become the new official date handling API - a quick search says it won't).

I you feel it's overkill to introduce a new dependency like Joda, longs aren't all that bad to use for timestamp fields in objects, although I myself usually wrap them in j.u.D when passing them around, for type safety and as documentation.

gustafc