java.util.Date vs java.sql.Date

java.util.Date vs java.sql.Date

java.util.Datejava.sql.Date的比较:何时使用哪个?为什么?


恭喜你,你已经用jdbc:日期类处理击中了我最喜欢的宠物。

基本上,数据库通常支持至少三种形式的日期时间字段,分别是日期、时间和时间戳。每个类在JDBC中都有一个对应的类,并且每个类都扩展了java.util.Date。这三种语言的快速语义如下:

  • java.sql.Date对应于SQL日期,即存储年、月和日,而忽略小时、分钟、秒和毫秒。另外,sql.Date与时区无关。
  • java.sql.Time对应于SQL时间,很明显,它只包含有关小时、分钟、秒和毫秒的信息。
  • java.sql.Timestamp对应于精确到纳秒的SQL时间戳(注意,util.Date只支持毫秒!)可定制的精准度。

对于这三种类型使用JDBC驱动程序时,最常见的错误之一是类型处理不正确。这意味着sql.Date是特定于时区的,sql.Time包含当前年份、月份和日期等。

最后:用哪一个?

实际上,这取决于字段的SQL类型。PreparedStatement对所有三个值都有设定值,#setDate()sql.Date的设定值,#setTime()sql.Time的设定值,#setTimestamp()sql.Timestamp的设定值。

请注意,如果您使用ps.setObject(fieldIndex, utilDateObject);,实际上可以为大多数JDBC驱动程序提供一个正常的util.Date,这些驱动程序将愉快地吞食它,就像它是正确的类型一样,但是当您随后请求数据时,您可能会注意到您实际上丢失了一些东西。

我真的是说所有的日期都不应该使用。

我要说的是,将毫秒/纳秒保存为普通的长时间,并将它们转换为您正在使用的任何对象(强制性的Joda时间插头)。一种可以做的黑客方法是将日期组件作为一个长时间组件存储,例如现在将是20100221和154536123。这些神奇的数字可以在SQL查询中使用,并且可以从数据库移植到另一个,并允许您完全避免JDBC/JavaDeAP:s的这一部分。


后期编辑:从Java 8开始,既不使用EDCOX1,也不使用EDCOX1,也不使用EDCOX1 0。如果您完全可以避免使用它,而是更喜欢使用EDCOX1×25封装(基于JoDA)而不是其他任何东西。如果你不在Java 8上,这里是最初的回应:

java.sql.Date—当您调用使用它的库(如jdbc)的方法/构造函数时。否则不行。对于不显式处理JDBC的应用程序/模块,您不希望向数据库库引入依赖项。

java.util.Date—当使用它的库时。否则,由于以下几个原因,尽可能少地:

  • 它是可变的,这意味着每次你将它传递给一个方法或者从一个方法返回它时,你都必须对它做一个防御性的拷贝。

  • 它不能很好地处理日期,这倒是像你这样的人,认为日期处理类应该。

  • 现在,由于J.U.D做得不太好,引入了可怕的Calendar类。它们也是可变的,很难使用,如果你没有选择的话应该避免。

  • 还有更好的选择,比如JoDA时间API(,它甚至可以进入Java 7,并成为新的官方数据处理API ——一个快速搜索称它不会)。

如果您觉得引入一个新的依赖项(如joda)有点过分,那么在对象中使用时间戳字段并不是很糟糕,尽管我在传递它们时通常用J.U.D包装它们,以确保类型安全和作为文档。


使用java.sql.Date的唯一时间是在PreparedStatement.setDate中。否则,使用java.util.Date。说明ResultSet.getDate返回java.sql.Date,但可以直接分配给java.util.Date


我有同样的问题,我发现将当前日期插入准备好的语句中最简单的方法是:

1
preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));


Java中的JavaUTILDATE类代表一个特定的时刻(例如,2013,11月25日16:30:45到毫秒),但是DB中的日期数据类型仅表示日期(例如,2013 11月25日)。为了防止错误地将JavaUTILDATE对象提供给数据库,Java不允许您直接将SQL参数设置为JavaUTILDATE:

1
2
3
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, d); //will not work

但它仍然允许您通过强制/意图来实现这一点(那么,DB驱动程序将忽略小时和分钟)。这是通过java.sql.date类完成的:

1
2
3
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, new java.sql.Date(d.getTime())); //will work

Java.Q.L.Dead对象可以及时存储一个时刻(以便于从Java.U.D.Dead构造),但是如果您试图请求它的小时数(强制执行它仅作为日期的概念),就会抛出异常。DB驱动程序应该能够识别这个类,并且只需要在几个小时内使用0。试试这个:

1
2
3
4
5
6
public static void main(String[] args) {
  java.util.Date d1 = new java.util.Date(12345);//ms since 1970 Jan 1 midnight
  java.sql.Date d2 = new java.sql.Date(12345);
  System.out.println(d1.getHours());
  System.out.println(d2.getHours());
}