Date vs java.sql.Date

java.util.Datejava.sql.Date: 什么时候使用哪个? 为什么?

302821 次浏览

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

祝贺您,您已经解决了JDBC最让我头疼的问题:日期类处理。

基本上,数据库通常至少支持三个形式的datetime字段,即日期、时间和时间戳。它们在JDBC和每个扩展java.util.Date中都有相应的类。这三者的快速语义如下:

  • java.sql.Date对应于SQL DATE,这意味着它存储了年、月、日,而小时,分钟,秒和毫秒被忽略。此外,sql.Date不受时区限制。
  • java.sql.Time对应于SQL TIME,很明显,它只包含关于小时,分钟,秒和毫秒的信息。
  • java.sql.Timestamp对应于SQL时间戳,它是精确到纳秒的日期(注意,util.Date只支持毫秒!),精度可自定义。

这意味着sql.Date是特定于时区的,sql.Time包含当前的年、月和日等等。

最后:用哪一个呢?

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

请注意,如果您使用ps.setObject(fieldIndex, utilDateObject);,您实际上可以给大多数JDBC驱动程序一个正常的util.Date,它们会很高兴地吞噬它,就好像它是正确的类型一样,但是当您之后请求数据时,您可能会注意到您实际上丢失了一些东西。

我的意思是,这些日期都不应该使用。

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

从Java 8开始,你不应该使用java.util.Datejava.sql.Date,如果你可以避免它,而宁愿使用java.time包(基于Joda)而不是其他任何包。如果你没有使用Java 8,以下是最初的回复:


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

java.util.Date -当使用使用它的库时。否则,尽可能少,原因如下:

  • 它是可变的,这意味着每次将它传递给方法或从方法返回它时,都必须对它进行防御性复制。

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

  • 现在,因为j.u.D没有很好地完成它的工作,可怕的Calendar类被引入。它们也是可变的,使用起来很糟糕,如果没有任何选择,应该避免使用。

  • 还有更好的替代品,比如Joda Time API (甚至可能会进入Java 7,成为新的官方日期处理API - a 快速搜索说它不会)。

如果您觉得引入像Joda这样的新依赖项有点过分,那么在对象中的时间戳字段中使用# eyz0并不那么糟糕,尽管我自己在传递它们时通常将它们包装在j.u.D中,以确保类型安全和作为文档。

date类在Java中表示一个特定的时刻(例如,.g。, 2013 Nov 25 16:30:45精确到毫秒),但是DB中的DATE数据类型只表示一个日期(例如,2013 Nov 25)。为了防止您错误地向DB提供Java .util. date对象,Java不允许您直接将SQL参数设置为Java .util. date:

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

但是它仍然允许您通过强制/意图来这样做(然后DB驱动程序将忽略小时和分钟)。这是通过java.sql.Date类完成的:

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

java.sql.Date对象可以存储时刻(因此很容易从java.util.Date构造它),但如果您试图询问它的小时数(以强制其仅为日期的概念),则会抛出异常。DB驱动程序应该能够识别这个类,并且只使用0表示小时数。试试这个:

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

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

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

java.util.Date表示具有毫秒精度的特定时刻。它表示不带时区的日期和时间信息。date类实现了可序列化、可克隆和可比较的接口。它由java.sql.Datejava.sql.Timejava.sql.Timestamp接口继承。

java.sql.Date扩展了java.util.Date类,它表示没有时间信息的日期,只应该在处理数据库时使用。为了符合SQL DATE的定义,java.sql.Date实例包装的毫秒值必须“规范化”,方法是在实例关联的特定时区中将小时、分钟、秒和毫秒设置为零。

它继承了java.util.Date的所有公共方法,如getHours()getMinutes()getSeconds()setHours()setMinutes()setSeconds()。由于java.sql.Date不存储时间信息,它覆盖了来自# eyz0的所有时间操作,所有这些方法在调用时会抛出java.lang.IllegalArgumentException,这从它们的实现细节中可以看出。

博士tl;

用都没有。

既不

java.util.Date vs . java.sql.Date:什么时候使用哪个,为什么?

这两个类都很糟糕,在设计和实现上都有缺陷。避免使用<罢工>瘟疫> < /罢工 冠状病毒

应该使用JSR 310中定义的java.time类。这些类是用于处理日期-时间处理的行业领先框架。它们完全取代了可怕的遗留类,如DateCalendarSimpleDateFormat等。

# EYZ0

第一个,java.util.Date表示UTC中的一个时刻,表示与UTC的0小时-分钟-秒的偏移量。

# EYZ0

现在被java.time.Instant取代。

Instant instant = Instant.now() ;  // Capture the current moment as seen in UTC.

# EYZ0

Instantjava.time的基本构建块类。为了获得更大的灵活性,为了同样的目的,可以将OffsetDateTime设置为ZoneOffset.UTC:表示UTC时间。

OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;

您可以使用PreparedStatement::setObjectJDBC 4.2或更高版本将该对象发送到数据库。

myPreparedStatement.setObject( … , odt ) ;

检索。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

# EYZ0

java.sql.Date类也很糟糕,过时了。

该类只表示日期,没有时间和时区。不幸的是,在一个糟糕的设计中,这个类继承了java.util.Date,它表示一个时刻(一个UTC时间的日期)。因此,这个类只是假装只有日期,而实际上携带了一个时间和UTC的隐式偏移量。这引起了很多困惑。永远不要使用这个类。

# EYZ0

相反,使用java.time.LocalDate只跟踪一个日期(年、月、月中的一天),而不需要任何时间、任何时区或偏移量。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate ld = LocalDate.now( z ) ;    // Capture the current date as seen in the wall-clock time used by the people of a particular region (a time zone).

发送到数据库。

myPreparedStatement.setObject( … , ld ) ;

检索。

LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;

 Java(包括传统和现代)和标准SQL中的日期-时间类型表


关于# EYZ0

< em > java.time < / em >框架内置于Java 8及更高版本中。这些类取代了麻烦的旧的遗产日期-时间类,如java.util.DateCalendar, &# EYZ7。

要了解更多信息,请参阅< < em >甲骨文教程/ em >。搜索Stack Overflow可以找到很多例子和解释。规格是JSR 310

< em > Joda-Time < / em >项目,现在在维护模式中,建议迁移到java.time类。

您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要java.sql.*类。

从哪里获取java。时间类?