java.util.Date
vs java.sql.Date
: when to use which and why?
相关问题
- Delete Messages from a Topic in Apache Kafka
- Jackson Deserialization not calling deserialize on
- SQL join to get the cartesian product of 2 columns
- sql execution latency when assign to a variable
- How to maintain order of key-value in DataFrame sa
LATE EDIT: Starting with Java 8 you should use neither
java.util.Date
norjava.sql.Date
if you can at all avoid it, and instead prefer using thejava.time
package (based on Joda) rather than anything else. If you're not on Java 8, here's the original response: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).If you feel it's overkill to introduce a new dependency like Joda,
long
s 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.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. Additionallysql.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 thatutil.Date
only supports milliseconds!) with customizable precision.One of the most common bugs when using 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 forsql.Date
,#setTime()
forsql.Time
and#setTimestamp()
forsql.Timestamp
.Do note that if you use
ps.setObject(fieldIndex, utilDateObject);
you can actually give a normalutil.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.
I had the same issue, the easiest way i found to insert the current date into a prepared statement is this one:
The java.util.Date class in Java represents a particular moment in time (e,.g., 2013 Nov 25 16:30:45 down to milliseconds), but the DATE data type in the DB represents a date only (e.g., 2013 Nov 25). To prevent you from providing a java.util.Date object to the DB by mistake, Java doesn’t allow you to set a SQL parameter to java.util.Date directly:
But it still allows you to do that by force/intention (then hours and minutes will be ignored by the DB driver). This is done with the java.sql.Date class:
A java.sql.Date object can store a moment in time (so that it’s easy to construct from a java.util.Date) but will throw an exception if you try to ask it for the hours (to enforce its concept of being a date only). The DB driver is expected to recognize this class and just use 0 for the hours. Try this:
The only time to use
java.sql.Date
is in aPreparedStatement.setDate
. Otherwise, usejava.util.Date
. It's telling thatResultSet.getDate
returns ajava.sql.Date
but it can be assigned directly to ajava.util.Date
.