tl;博士
我应该使用 java.util.Date 还是 java.sql.Date?
都没有。
从JDBC 4.2 及更高版本开始,两者都已过时。请改用 java.time 类。
-
仅日期值
对于类似于 SQL 标准 DATE 的数据库类型,请使用 java.time.LocalDate。
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
myPreparedStatement.setObject( ld , … ) ;
-
以 UTC 值表示的日期
对于类似于 SQL 标准 TIMESTAMP WITH TIME ZONE 的数据库类型,请使用 java.time.Instant。
Instant instant = myResultSet.getObject( … , Instant.class ) ;
myPreparedStatement.setObject( instant , … ) ;
详情
问题和其他答案似乎过度思考了这个问题。 java.sql.Date 只是一个java.util.Date,其时间设置为00:00:00。
来自the java.sql.Date doc(斜体字是我的)……
上课日期
java.lang.Object
java.util.Date ← 继承自 j.u.Date
java.sql.Date
…
一个毫秒值的瘦包装器,允许 JDBC 将其识别为 SQL DATE 值。毫秒值表示自 1970 年 1 月 1 日 00:00:00.000 GMT 以来经过的毫秒数。 ← 时间设置为零,格林威治标准时间/世界标准时间午夜
为了符合 SQL DATE 的定义,由 java.sql.Date 实例包装的毫秒值必须通过在特定时区中将小时、分钟、秒和毫秒设置为零来进行“规范化”。实例已关联。
仅日期与日期时间
核心问题是:
-
SQL
在 SQL 中,DATE 数据类型仅存储日期,没有时间。
-
JAVA
在与早期 Java 版本捆绑在一起的设计糟糕的日期时间库中,它们未能包含一个表示仅日期的类。
Java 团队没有创建一个仅包含日期的类,而是做了一个可怕的 hack。他们使用他们的日期时间类(错误命名的java.util.Date 类,包含日期和时间)并将其扩展为让实例将其时间设置为午夜UTC、@987654394 @。那个hack,j.u.Date的那个子类,是java.sql.Date。
所有这些黑客行为、糟糕的设计和错误的命名都造成了混乱。
使用哪个
那么什么时候用哪个?简单,在切断混乱之后。
- 在读取或写入数据库的仅日期列时,请使用
java.sql.Date,因为它笨拙地试图掩盖其时间。
- 在 Java 中需要时间和日期的任何其他地方,请使用
java.util.Date。
- 当您手头有 java.sql.Date 但需要 java.util.Date 时,只需传递 java.sql.Date。作为一个子类,java.sql.Date是java.util.Date。
更好
在现代 Java 中,您现在可以选择体面的日期时间库来替代与 Java 捆绑在一起的旧的、臭名昭著的麻烦 java.util.Date、Calendar、SimpleTextFormat 和 java.sql.Date 类。主要选择有:
两者都提供LocalDate 类来仅表示日期,没有时间和时区。
更新到 JDBC 4.2 或更高版本的JDBC driver 可用于直接与数据库交换 java.time 对象。这样我们就可以彻底抛弃 java.util.* 和 java.sql.* 包中的日期时间类这种丑陋的烂摊子了。
设置对象 |获取对象
Oracle 发布的This article 解释说,如果您调用getObject 和setObject 方法,Java 8 中的 JDBC 已经透明地更新,以将 SQL DATE 值映射到新的 java.time.LocalDate 类型。
在钝化的语言中,JDBC 4.2 update spec 的底部确认了该文章,并在getObject 和setObject 方法中添加了新的映射。
myPreparedStatement.setObject( … , myLocalDate ) ;
……和……
LocalDate myLocalDate = myResultSet.getObject( … , LocalDate.class ) ;
转换
规范还说,java.sql.Date 类中添加了新方法,用于来回转换为 java.time.LocalDate。
时区
旧的java.util.Date、java.sql.Date 和java.sql.Timestamp 始终位于UTC。前两个(至少)有一个深埋在源代码中的时区,但仅在表面下使用,例如 equals 方法,并且没有 getter/setter。
更令人困惑的是,他们的 toString 方法应用了 JVM 当前的默认时区。所以对于天真的程序员来说,似乎他们有一个时区,但他们没有。
隐藏时区和toString 行为是避免这些麻烦的旧遗留类的众多原因中的两个。
使用java.time(Java 8 及更高版本)编写您的业务逻辑。 java.time 缺少的地方,使用Joda-Time。 java.time 和 Joda-Time 都有方便的方法在需要的地方来回切换旧类。
替换:
Instant 类表示UTC 时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。
所有三个java.time.Local… 类都缺少time zone 或offset-from-UTC 的任何概念。
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。