java.util.Date vs java.sql.Date

fly*_*ire 487 java sql datetime date jdbc

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

Esk*_*sko 571

恭喜你,你已经用JDBC打了我最喜欢的宠物:日期类处理.

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

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

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

最后:哪一个使用?

真的,取决于该字段的SQL类型.PreparedStatement有三个值的setter,#setDate()是for sql.Date,#setTime()for sql.Time#setTimestamp()for的sql.Timestamp.

请注意,如果您使用,ps.setObject(fieldIndex, utilDateObject);您实际上可以util.Date为大多数JDBC驱动程序提供正常操作,这些驱动程序会愉快地吞噬它,就好像它的类型正确,但是当您之后请求数据时,您可能会注意到您实际上缺少了某些东西.

我真的说没有任何日期应该被使用.

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

  • 也许,然而DBA:通常倾向于选择RDBMS并直接拒绝与RDBMS无关的所有内容(*我正在看着你,Oracle粉丝*),而Java应用程序预计会与所有这些应用程序一起工作.我个人不喜欢把我的逻辑放到DB中. (26认同)
  • 很好的答案.但是,对于DBA来说,存储日期是否有点不友好? (16认同)
  • 我提到它是一个常见的*错误*它是TZ特定的,而它不符合规范. (3认同)
  • 我的mysql列是一个日期时间,但正在执行ps.setDate(new java.sql.Date(myObject.getCreatedDate().getTime())); 我正在失去毫秒部分,如何解决这个问题? (2认同)
  • 不要丢失你的毫秒:new java.sql.Timestamp(utilDate.getTime()) (2认同)

gus*_*afc 58

后期编辑:从Java 8开始,您既不应该使用java.util.Date也不 应该使用java.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.time而不是java.sql?我在声明中真的很有趣,但我想明白为什么:) (5认同)

Pau*_*lin 19

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

  • Ehm,ResultSet#getDate()返回sql.Date(扩展了util.Date). (3认同)
  • @Esko - "嗯",我在你评论(和downvoted)之前解决了这个问题. (3认同)
  • 当前者扩展后者时,为什么要告诉“ java.sql.Date”可以分配给“ java.util.Date”呢?您要说明的重点是什么? (2认同)

Bas*_*que 11

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.
Run Code Online (Sandbox Code Playgroud)

java.time.OffsetDateTime

Instantjava.time的基本构建块类。为了获得更大的灵活性,请使用OffsetDateTimeset toZoneOffset.UTC来实现相同的目的:用 UTC 表示一个时刻。

OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
Run Code Online (Sandbox Code Playgroud)

您可以通过使用这个对象发送到数据库PreparedStatement::setObjectJDBC 4.2或更高版本。

myPreparedStatement.setObject( … , odt ) ;
Run Code Online (Sandbox Code Playgroud)

取回。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Run Code Online (Sandbox Code Playgroud)

java.sql.Date

java.sql.Date门课也很糟糕而且过时了。

此类仅用于表示日期,没有时间和时区。不幸的是,在一个可怕的设计黑客中,这个类继承自java.util.Datewhich 代表一个时刻(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).
Run Code Online (Sandbox Code Playgroud)

发送到数据库。

myPreparedStatement.setObject( … , ld ) ;
Run Code Online (Sandbox Code Playgroud)

取回。

LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
Run Code Online (Sandbox Code Playgroud)

Java(旧版和现代版)和标准 SQL 中的日期时间类型表


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

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

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

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

从哪里获得 java.time 类?

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

  • 支持用电晕病毒取代鼠疫参考。现在更相关了。 (2认同)

Isr*_*elm 10

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

preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
Run Code Online (Sandbox Code Playgroud)

  • 无法获得时区。 (2认同)