在java.util.Date或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;博士
我应该使用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
。
从java.sql.Date doc (斜体文本是我的)…
上课日期
java.lang.Objectinheritance
java.util.Date ←从juDateinheritance
java.sql.Date
…
一个围绕毫秒值的瘦包装器,允许JDBC将其标识为SQL DATE值。 毫秒值表示自1970年1月1日00:00:00.000 GMT以来经过的毫秒数。 ←时间设置为零,格林威治标准时间午夜/ UTC
为了符合SQL DATE的定义,java.sql.Date实例包含的毫秒值必须通过在与实例关联的特定时区中将小时,分钟,秒和毫秒设置为零来“标准化”。 。
仅日期与日期时间
核心问题是:
- SQL
在SQL中,DATE
数据类型仅存储日期,而不存在时间。 - JAVA
在与早期Java版本捆绑在一起的设计糟糕的日期时间库中,它们未能包含一个表示仅限日期的类。
Java团队没有创建一个仅限日期的类,而是制造了一个糟糕的黑客 。 他们使用了他们的日期时间类(名称错误的java.util.Date
类,包含日期和时间)并将其扩展为将实例设置为时间到午夜UTC , 00:00:00 。 那个hack,即juDate的子类,是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发布的这篇文章解释说,如果调用getObject
和setObject
方法,Java 8中的JDBC已经透明地更新,以将SQL DATE
值映射到新的java.time.LocalDate类型。
在钝语言中, JDBC 4.2更新规范的底部确认了该文章,并将新映射添加到getObject
和setObject
方法中。
myPreparedStatement.setObject( … , myLocalDate ) ;
…和…
LocalDate myLocalDate = myResultSet.getObject( … , LocalDate.class ) ;
兑换
该规范还说java.sql.Date类中添加了新方法,可以来回转换为java.time.LocalDate。
-
public java.time.instant toInstant()
-
public java.time.LocalDate toLocalDate()
-
public static java.sql.Date valueOf(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都有方便的方法来回传需要的旧类。
替换:
-
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.Date
, Calendar
和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增加了一些小function和修复。
- Java SE 6和Java SE 7
- 许多java.timefunction都被反向移植到ThreeTen-Backport中的 Java 6和7。
- Android的
- 更高版本的Android捆绑java.time类的实现。
- 对于早期的Android(<26), ThreeTenABP项目采用ThreeTen-Backport (如上所述)。 请参见如何使用ThreeTenABP ….
ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。 您可以在这里找到一些有用的课程,如Interval
, YearWeek
, YearQuarter
等。
通常,我发现使用java.util.Date
是可取的,因为您可以在程序中的任何位置使用它,而无需转换类型或使用特定于SQL的代码污染应用程序。
我不知道’java.sql.Date’会更适合的情况。
那么,根据这篇文章你可以使用没有@Temporal
注释的javax.sql.Date
,这可以节省一些编码。 但是java.util.Date
更易于在整个应用程序中使用。
所以我会用
@Column(name = "date") @Temporal(TemporalType.DATE) private java.util.Date date;
根据Java doc,建议根据底层数据库使用适当的Date类型。 但是,对于Java 8,已经提供了java.time包下的一组丰富的类,如果应用程序是用Java 8编写的,则必须使用它。
类javaxjava.sql.Date扩展了java.util.Date,对miliseconds容器进行了少量更改,以便它可以有效地支持Database DATE类型。 这样,我们可以保存从实体类输入的@Temporal注释。
但是,java.util.Date可用于在整个应用程序中实现更好的可伸缩性,以便它可以轻松地用于存储时间和日期。