我应该使用 java.util.Date 还是切换到 java.time.LocalDate

Posted

技术标签:

【中文标题】我应该使用 java.util.Date 还是切换到 java.time.LocalDate【英文标题】:Should I use java.util.Date or switch to java.time.LocalDate 【发布时间】:2015-04-28 02:28:21 【问题描述】:

编辑:嗯,显然它过于基于意见,所以让我尝试更准确地重新措辞 -

在不需要任何向后兼容性的 Java 代码中使用 LocalDate、LocalTime 等是否有任何明确的警告或缺点?如果是,它们是什么?

我正在寻找诸如“当前的 EE 库 X 和 Y 不能与 LocalDate 正常工作”或“这个非常有用的模式被 LocalTime 破坏”等内容。


(这里是原始问题供参考)

在 Java 8 中,引入了一个新的时间 API,即 java.time.LocalDate 等,但 java.util.Date 并未标记为已弃用。

我正在编写一个不需要向后兼容的新项目。我应该只使用 LocalDate、LocalDateTime 等吗?与旧的 java.util.Date 相比,使用这个新 API 有什么缺点吗?

特别是 - 我将主要使用 JDBC。从我所见 JDBC 处理 java.util.Date 很好。它也适合 LocalDate 吗?

搜索产生了很多网站告诉如何从一种格式转换为另一种格式,但对于新代码是否应该使用旧 API 没有明确的答案。

谢谢。

【问题讨论】:

good old java.util.Date - 它很旧,但不好。新代码应使用新 API。 创建全新的日期 API 是有原因的。如果您有一个新建项目,请使用 Java 8 引入的 API。 请使用新的 API。 :-P Java 对使用 @Deprecated 注释来处理不好但不会被删除的东西持谨慎态度。 Oracle 自己的文档给出了弃用 API 的三个主要原因:"It is insecure, buggy, or highly inefficient; It is going away in a future release; It encourages bad coding practices." 这些是否适用于 java.util.Date 可能是一个见仁见智的问题。 【参考方案1】:

尽管有名字,java.util.Date 可用于存储日期和时间(它存储自纪元以来的 UTC 毫秒偏移量)

由于功能更强大,我肯定会使用新的 API:

更简单的格式/解析。 API 有自己的格式/解析方法 API 包括加法/减法运算(minusMinutesplusDays 等)

以上都不在java.util.Date

Old Date 也可以像这样转换为LocalDateTime

    Date oldDate = ...
    LocalDateTime newDateTime = 
      LocalDateTime.from(Instant.ofEpochMilli(oldDate.getTime()));

【讨论】:

那么在你看来,是时候放弃旧的 Date 了吗? @ShedomWei 这完全取决于您的项目要求。 OP 决定坚持使用旧日期,因为“显然 mysql 连接器 J 不支持 Java 8”(2015 年 3 月 3 日意大利 0:40)。【参考方案2】:

我正在添加到correct Answer by Ole V.V.

JDBC 4.2

特别是 - 我将主要使用 JDBC。

JDBC 4.2 添加了对与数据库交换 java.time 对象的支持。请参阅 PreparedStatement::setObjectResultSet::getObject 方法。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate today = LocalDate.now( z ) ;
myPreparedStatement.setObject( … , today ) ;

检索。

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

出于我无法理解的原因,JDBC 规范确实需要支持两个最常用的类:InstantZonedDateTime。您的数据库和JDBC driver 可能会也可能不会添加对这些的支持。

如果没有,您可以轻松转换。以OffsetDateTime 开头,JDBC 需要支持。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

要通过特定地区(时区)的人们使用的挂钟时间查看这一时刻,请应用ZoneId 以获取ZonedDateTime 对象。

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant() ;

要适应 UTC,请提取 Instant。根据定义,Instant 始终采用 UTC。

Instant instant = odt.toInstant() ;

您可以转换另一种方式,写入数据库。

myPreparedStatement.setObject( … , zdt.toOffsetDateTime() ;  // Converting from `ZonedDateTime` to `OffsetDateTime`. Same moment, same point on the timeline, different wall-clock time.

…和:

myPreparedStatement.setObject( … , instant.atOffset( ZoneOffset.UTC ) ) ;  // Converting from `Instant` to `OffsetDateTime`. Same moment, same point on the timeline, and even the same offset. `OffsetDateTime` is a more flexible class with abilities such as (a) applying various offsets and (b) flexible formatting when generating text, while `Instant` is meant to be a more basic building-block class. 

注意naming convention used in java.timeatfromtowith,等等。


关于java.time

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

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

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

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

从哪里获得 java.time 类?

Java SE 8Java SE 9Java SE 10Java SE 11 和更高版本 - 具有捆绑实现的标准 Java API 的一部分。 Java 9 添加了一些小功能和修复。 Java SE 6Java SE 7 大部分 java.time 功能在ThreeTen-Backport 中向后移植到 Java 6 和 7。 Android java.time 类的 android 捆绑包实现的更高版本。 对于早期的 Android (ThreeTenABP 项目适应 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 和more。

【讨论】:

ThreeTenBackport 是一个很好的库,但现在对于 Android (2021 年及之后),official documents 和 JakeWharton(ThreeTen 的作者)建议使用 Java 8+ API 去糖支持。 【参考方案3】:

Java 8 及更高版本:不用担心

不,如果您使用的是 Java 8 或更高版本(内置该 API),那么您没有理由不使用 java.time,这是现代 Java 日期和时间 API。

唯一可以简单考虑的,就是你已经排除的那个。

我正在写一个新项目,它不需要向后兼容。

即使是为了向后兼容,您也可以安全地使用 java.time,因为转换方法内置于 Java 8 的旧类中。

Java 6 和 7:称重

如果您使用的是 Java 6 或 7,则需要将 ThreeTen-Backport 用于 java.time,在 ThreeTenABP 中进一步适用于 API 级别 26 以下的 Android。如果您只做很少非常简单的日期和时间工作,并且前向兼容性不是问题,您可以考虑外部依赖是否值得。请考虑到您的外部依赖项只是 Java 8 及更高版本中内置内容的反向移植,因此非常可靠,因此您只需要它,直到您迁移到 Java 8 或更高版本。届时您可以更改导入、重新测试并取消反向移植。

您的可考虑负债示例

当前的 EE 库 X 和 Y 不能与 LocalDate 一起正常工作

有一些例子,还有 JDK 中的库类。我的选择是在我自己的代码中使用 java.time,并且仅在调用尚未接受 java.time 类型的 API 之前进行转换。相反,如果我从 API 获得一个过时类的实例,首先将其转换并使用 java.time 其余部分。

LocalTime 打破了这种非常有用的模式

我不知道这样的模式。相反,java.time 使用模式不可变对象工厂方法,这与大多数旧类不同。

【讨论】:

以上是关于我应该使用 java.util.Date 还是切换到 java.time.LocalDate的主要内容,如果未能解决你的问题,请参考以下文章

在 java.util.Date 或 java.sql.Date 之间进行选择

java.util.Date和java.util.Calendar及相关类

JSON `date(...)` 到 `java.Util.Date` 使用 `org.json`

new java.util.Date() 得到的时间与系统时间不一样,为啥?

如何设置 java.util.Date 的时区?

使用对象 java.util.Date 时出现错误的星期几 [重复]