繁体   English   中英

java.util.Date 与 java.sql.Date

[英]java.util.Date vs java.sql.Date

java.util.Date vs java.sql.Date :何时使用哪个以及为什么?

恭喜,您已经对 JDBC:日期类处理感到不满。

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

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

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

最后:使用哪个?

取决于字段的 SQL 类型,真的。 PreparedStatement具有所有三个值的设置器, #setDate()sql.Date#setTime()sql.Time#setTimestamp()sql.Timestamp

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

我真的是说根本不应该使用任何日期。

我所说的是将毫秒/纳秒保存为普通 long 并将它们转换为您正在使用的任何对象(强制性 joda-time plug )。 一种可行的方法是将日期组件存储为一个长时间组件,将时间组件存储为另一个组件,例如现在将是 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 - 使用使用它的库时。 否则,尽可能少,原因如下:

  • 它是可变的,这意味着每次将它传递给方法或从方法返回它时,都必须制作一个防御性副本。

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

  • 现在,因为 juD 不能很好地完成它的工作,所以引入了可怕的Calendar类。 它们也是可变的,并且很难使用,如果您别无选择,应该避免使用它们。

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

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

唯一一次使用java.sql.Date是在PreparedStatement.setDate 否则,使用java.util.Date 它告诉我们ResultSet.getDate返回一个java.sql.Date但它可以直接分配给一个java.util.Date

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

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

tl;博士

都不用。

两者都不

java.util.Date 与 java.sql.Date:何时使用哪个以及为什么?

这两个类都很糟糕,在设计和实现上都有缺陷。 避免像 瘟疫 冠状病毒一样

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

java.util.Date

第一个java.util.Date表示 UTC 中的一个时刻,这意味着与 UTC 零时分秒的偏移量。

java.time.Instant

现在由java.time.Instant取代。

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

java.time.OffsetDateTime

Instantjava.time的基本构建块类。 为了更灵活,使用OffsetDateTime设置为ZoneOffset.UTC为了同样的目的:代表UTC片刻。

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

您可以通过在JDBC 4.2 或更高版本中使用PreparedStatement::setObject将此对象发送到数据库。

myPreparedStatement.setObject( … , odt ) ;

取回。

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

java.sql.Date

java.sql.Date类也很糟糕而且已经过时了。

此类仅用于表示日期,没有时间和时区。 不幸的是,在一个可怕的设计黑客中,这个类继承自java.util.Date ,它代表一个时刻(UTC 时间的日期)。 所以这个类只是假装只有日期​​,而实际上携带了一个时间和 UTC 的隐式偏移量。 这引起了很多混乱。 永远不要使用这个类。

java.time.LocalDate

相反,使用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 中的日期时间类型表


关于java.time

java.time框架内置于 Java 8 及更高版本中。 这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar ,和SimpleDateFormat

要了解更多信息,请参阅Oracle 教程 并在 Stack Overflow 上搜索许多示例和解释。 规范是JSR 310

现在处于维护模式Joda-Time项目建议迁移到java.time类。

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

从哪里获得 java.time 类?

哪个 java.time 库与哪个版本的 Java 或 Android 一起使用的表

Java 中的 java.util.Date 类表示特定的时刻(例如,2013 Nov 25 16:30:45 到毫秒),但 DB 中的 DATE 数据类型仅表示日期(例如, 2013 年 11 月 25 日)。 为了防止您错误地向 DB 提供 java.util.Date 对象,Java 不允许您直接将 SQL 参数设置为 java.util.Date:

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

但它仍然允许您通过强制/意图来做到这一点(然后小时和分钟将被数据库驱动程序忽略)。 这是通过 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 构造)但是如果您尝试询问它的小时数(以强制其概念为仅限日期)。 数据库驱动程序应该识别这个类并且只使用 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());
}

java.util.Date表示具有毫秒精度的特定时刻。 它表示没有时区的日期和时间信息。 java.util.Date 类实现了 Serializable、Cloneable 和 Comparable 接口。 它由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不存储时间信息,它会覆盖java.util.Date所有时间操作,如果从它们的实现细节中可以明显看出,所有这些方法都会抛出java.lang.IllegalArgumentException异常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM