在 java.util.Date 或 java.sql.Date 之间进行选择tl;博士详仅日期与日期时间使用哪种甚至更好时区关于 java.time

2022-09-02 02:51:36

我应该使用java.util.Date还是java.sql.Date?

我有一个VisualFox数据库,并且我已经使用适当的jdbc类型4驱动程序使用IntelliJ Idea向导检索了实体。

ide(或驱动程序)已将日期字段创建为时间戳。但是,日期字段不是时间戳,而是日期字段,它们仅存储年、月和日。

所以我想知道我是否应该切换到java.util.Date或java.sql.Date。乍一看,我认为java.sql.Date应该是合适的,但它有许多方法被声明为已弃用。


答案 1

tl;博士

我应该使用java.util.Date还是java.sql.Date?

也不。

两者都已过时,因为 JDBC 4.2 及更高版本。请改用 java.time 类。

  • 仅日期值
    对于类似于 SQL 标准的数据库类型,请使用 。DATEjava.time.LocalDate
    • LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
    • myPreparedStatement.setObject( ld , … ) ;
  • 日期,其中的时间采用 UTC 值
    对于类似于 SQL 标准的数据库类型,请使用 。TIMESTAMP WITH TIME ZONEjava.time.Instant
    • Instant instant = myResultSet.getObject( … , Instant.class ) ;
    • myPreparedStatement.setObject( instant , … ) ;

这个问题和其他答案似乎过度思考了这个问题。java.sql.Date 只是一个 java.util.Date,其时间设置为 00:00:00

来自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 以来经过的毫秒数。← 一天中的时间设置为零,午夜 GMT/UTC

为了符合 SQL DATE 的定义,必须通过将实例关联的特定时区中的小时、分钟、秒和毫秒设置为零来“规范化”由 java.sql.Date 实例包装的毫秒值。

仅日期与日期时间

核心问题是:

  • SQL
    在 SQL 中,数据类型仅存储日期,而不存储一天中的时间。DATE
  • JAVA
    在与 Java 早期版本捆绑在一起的设计糟糕的日期时间库中,它们未能包含一个类来表示仅日期。

Java团队没有创建一个仅限日期的类,而是进行了一次可怕的黑客攻击。他们采用日期时间类(错误命名的java.util.Date类,包含日期和时间)并将其扩展为一个实例将其时间设置为午夜UTC,。那个黑客,j.u.Date的子类,是java.sql.Date00:00:00

所有这些黑客攻击,糟糕的设计和错误命名已经造成了令人困惑的混乱。

使用哪种

那么什么时候使用哪个呢?简单,经过切破混乱。

  • 读取或写入数据库的“仅日期”列时,请使用,因为它笨拙地尝试掩盖其时间。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 驱动程序可用于直接与数据库交换 java.time 对象。然后,我们可以完全放弃 java.util.* 和 java..sql.* 包中的日期时间类的丑陋混乱。

设置对象|获取对象

Oracle 发布的这篇文章解释说,Java 8 中的 JDBC 已透明地更新,以便在调用 和 方法时将 SQL 值映射到新的 java.time.LocalDate 类型。DATEgetObjectsetObject

在钝语言中,JDBC 4.2 更新规范的底部确认了该文章,并在 和 方法中添加了新的映射。getObjectsetObject

myPreparedStatement.setObject( … , myLocalDate ) ;

...和。。。

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

转换

该规范还说,java.sql.Date类中添加了新方法,以来回转换为java.time.LocalDate。

时区

旧的 、 和 始终采用 UTC 格式。前两个(至少)在其源代码中有一个深埋的时区,但只在表面下使用,例如方法,并且没有getter/setter。java.util.Datejava.sql.Datejava.sql.Timestampequals

更令人困惑的是,他们的方法应用JVM的当前默认时区。因此,对于天真的程序员来说,他们似乎有一个时区,但他们没有。toString

埋藏的时区和行为都是避免这些麻烦的旧遗留类的众多原因中的两个。toString

使用 java.time(Java 8 及更高版本)编写业务逻辑。在java.time缺少的地方,使用Joda-Time。java.time和Joda-Time都有方便的方法,可以在需要时与旧类来回切换。

更换:

Instant 类以 UTC 格式表示时间轴上的某个时刻,分辨率为纳秒(最多九 (9) 位小数)。

所有这三个类都缺少任何时区与 UTC 的偏移量概念。java.time.Local…


关于 java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧日期时间类,如java.util.DateCalendarSimpleDateFormat

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

要了解更多信息,请参阅 Oracle 教程。搜索 Stack Overflow 以获取许多示例和解释。规格是JSR 310

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

从哪里获取 java.time 类?

ThreeTen-Extra 项目通过其他类扩展了 java.time。这个项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuarter


答案 2

好吧,根据本文,您可以在没有注释的情况下使用,这可以节省您的一些编码。但是,在整个应用程序中更易于使用。javax.sql.Date@Temporaljava.util.Date

所以我会用

@Column(name = "date")
@Temporal(TemporalType.DATE)
private java.util.Date date;

推荐