在 java.time API 和 java.util.Date 之间转换

Convert between java.time API and java.util.Date

从 Android Studio 4 开始,伟大的 java.time API 可供 Android 使用。

在我的项目中,我想逐渐从 java.util.Date 迁移到新的 API。

如何在两种格式之间进行转换?

首先,我想指出严重的差异。

java.time

java.time API 在明确不同的时间概念方面做得很好,例如如果你想表示某个时间点或Duration。 在第一种情况下,您可以选择是否要表示日期、时间或两者,以及是否希望它具有时区意识,例如

  • LocalDate(日期,无时间,无时区)
  • LocalDateTime(日期、时间,无时区)
  • ZonedDateTime(日期、时间、时区)

一个 Instant 表示时间戳(UTC 中自 01.01.1970 以来的纳秒数)。所以它是时间的机器表示,也是其他 classes.

的构建块

要查看所有 class,请查看 java.time API documentation

java.util.Date

Date的方法建议它代表一个日期和时间。在内部,它仅存储时间戳(自 01.01.1970 UTC 以来的毫秒数)并且没有时区。

创建它的推荐方法是使用时区感知 Calendar class。但是,Date 本身是通过隐式使用计算机 运行 所在的时区生成的。 调用 toString() 格式化输出可能会显示时区,但它是从 Calendar 实例外部获得的,这导致混淆 Date 会存储时区。

总而言之,API 设计不佳,可能会造成混淆。 java.time 优越得多,应尽可能使用。

遗留代码的适配器

那两个API是怎么连接的呢? -> 通过 Instant.

在 java 8 java.util.Date 中使用两种方法进行了扩展:

  • public static Date from(Instant instant)
  • public Instant toInstant()

这是 API 之间的内置桥梁!

我们可以在此基础上构建更多的适配器函数。 这是一个示例(在 Kotlin 中),其中包含 classes LocalDateLocalDateTime:

的转换
/**
 * java.util.Date has no explicit time zone but implicitly uses the system's time zone
 */
private val dateZoneId: ZoneId = ZoneId.systemDefault()

fun Date.toLocalDate(): LocalDate = toInstant().atZone(dateZoneId).toLocalDate()

fun LocalDate.toDate(): Date = Date.from(atStartOfDay(dateZoneId).toInstant())

fun Date.toLocalDateTime(): LocalDateTime = toInstant().atZone(dateZoneId).toLocalDateTime()

fun LocalDateTime.toDate(): Date = Date.from(atZone(dateZoneId).toInstant())