关于jpa:在java.util.Date或java.sql.Date之间进行选择

Choosing between java.util.Date or java.sql.Date

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

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

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

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


TL;博士

Should I use java.util.Date or java.sql.Date?

Ok.

都不是。

从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

  • <5233>
  • myPreparedStatement.setObject( instant , … ) ;
  • 细节

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

    从java.sql.Date doc(斜体文本是我的)...

    Class Date

    Ok.

    java.lang.Object

    Ok.

        java.util.Date        ← Inherits from j.u.Date

    Ok.

            java.sql.Date

    Ok.

    Ok.

    A thin wrapper around a millisecond value that allows JDBC to identify this as an SQL DATE value. A milliseconds value represents the number of milliseconds that have passed since January 1, 1970 00:00:00.000 GMT.  ← Time-of-day set to Zero, midnight GMT/UTC

    Ok.

    To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.

    Ok.

    仅日期与日期时间

    核心问题是:

  • SQL
    在SQL中,DATE数据类型仅存储日期,而不存在时间。
  • JAVA
    在与Java早期版本捆绑在一起的设计糟糕的日期时间库中,它们未能包含一个表示仅限日期的类。
  • Java团队没有创建一个仅限日期的类,而是制造了一个糟糕的黑客。他们采用了日期时间类(名称错误的java.util.Date类,包含日期和时间)并将其扩展为将实例设置为时间到午夜UTC,00:00:00。那个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类。主要选择是:

  • 乔达时间
  • java.time
    (受Joda-Time启发,由JSR 310定义,与Java 8捆绑在一起,由ThreeTen-Extra项目扩展)
  • 两者都提供LocalDate类来表示日期,没有时间和没有时区。

    更新到JDBC 4.2或更高版本的JDBC驱动程序可用于直接与数据库交换java.time对象。然后我们可以完全放弃丑陋的混乱,它是java.util。*和java.sql。*包中的日期时间类。

    setObject |的getObject

    Oracle发布的这篇文章解释了如果调用getObjectsetObject方法,Java 8中的JDBC已经透明地更新,以将SQL DATE值映射到新的java.time.LocalDate类型。

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

    1
    myPreparedStatement.setObject( … , myLocalDate ) ;

    …和…

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

    兑换

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

  • <5233>
  • public java.time.LocalDate toLocalDate()
  • public static java.sql.Date valueOf(java.time.LocalDate)
  • 时区

    旧的java.util.Datejava.sql.Datejava.sql.Timestamp始终为UTC。前两个(至少)的源代码深埋在一个时区,但仅在表面下使用,如equals方法,并且没有getter / setter。

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

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

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

    替换:

  • java.util.Date替换为java.time.Instant
  • java.sql.Timestamp替换为java.time.Instant
  • java.sql.Date替换为java.time.LocalDate
  • java.sql.Time替换为java.time.LocalTime
  • Instant类表示UTC时间轴上的一个时刻,分辨率为纳秒(小数部分最多九(9)位)。

    所有三个java.time.Local…类都缺少任何时区概念或从UTC偏移。

    关于java.time

    java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧遗留日期时间类,例如java.util.DateCalendar和&amp; SimpleDateFormat

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

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

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

    从哪里获取java.time类?

  • Java SE 8,Java SE 9,Java SE 10及更高版本

  • 内置。
  • 带有捆绑实现的标准Java API的一部分。
  • Java 9增加了一些小功能和修复。
  • Java SE 6和Java SE 7

  • 许多java.time功能都被反向移植到Java 6&amp; 7在ThreeTen-Backport。
  • Android的

  • 更高版本的Android捆绑java.time类的实现。
  • 对于早期的Android(<26),ThreeTenABP项目采用ThreeTen-Backport(如上所述)。请参见如何使用ThreeTenABP ....
  • ThreeTen-Extra项目使用其他类扩展了java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的类,例如IntervalYearWeekYearQuarter等。

    好。


    那么,根据这篇文章你可以使用javax.sql.Date而不用@Temporal注释,这可以节省一些编码。但是java.util.Date更易于在整个应用程序中使用。

    所以我会用

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


    通常,我发现建议使用java.util.Date,因为您可以在程序中的任何位置使用它,而无需转换类型或使用特定于SQL的代码污染应用程序。

    我不知道'java.sql.Date'会更适合的情况。


    根据Java doc,建议根据底层数据库使用适当的Date类型。
    但是,使用Java 8,已经提供了java.time包下的一组丰富的类,如果应用程序是用Java 8编写的,则必须使用它。

    类javaxjava.sql.Date扩展了java.util.Date,对miliseconds容器进行了少量更改,以便它可以有效地支持Database DATE类型。这样,我们可以保存从实体类输入的@Temporal注释。

    但是,java.util.Date可用于在整个应用程序中实现更好的可伸缩性,以便它可以轻松地用于存储时间和日期。