Java 时间类转换都在这了,拿走--2022-01-14

大家好,我是指北君。

众所周知,Java 8 之前的 Date 相关的时间类非常的不好用。从 Java 8 之后开始加入了 LocalDate 等一系列更加现代化的时间类。

这就衍生出 Java 8 之前的 Date 需要和 LocalDate 互相转换的需求。今天指北君把这几年积累下来的转换代码分享给大家。

java.util.Date 与 java.time.LocalDate 之间的转换

在 Date 转换 LocalDate 的过程中,我们使用 Date 类中在 Java 8 新增的 toInstant() 方法进行转换。

当我们转换一个 Instant 对象时,需要使用 ZoneId,因为 Instant 对象是不分时区的–只是时间线上的点。

Instant 对象的 atZone(ZoneId zone) API 返回一个 ZonedDateTime,所以我们只需要使用 toLocalDate() 方法从中提取 LocalDate。

在这里我们使用的是系统默认的 ZoneId。

1
2
3
4
5
public LocalDate convertToLocalDateViaInstant(Date dateToConvert) {
    return dateToConvert.toInstant()
      .atZone(ZoneId.systemDefault())
      .toLocalDate();
}

还有一个类似的解决方案,但用不同的方式来创建一个 Instant 对象–使用 ofEpochMilli() 方法。

1
2
3
4
5
public LocalDate convertToLocalDateViaMilisecond(Date dateToConvert) {
    return Instant.ofEpochMilli(dateToConvert.getTime())
      .atZone(ZoneId.systemDefault())
      .toLocalDate();
}

在我们继续之前,让我们也快速看一下旧的 java.sql.Date 类,以及它是如何被转换为 LocalDate 的。

从 Java 8 开始,我们可以在 java.sql.Date 上找到一个额外的 toLocalDate() 方法,这也给了我们一个将其转换为 java.time.LocalDate 的简单方法。

在这种情况下,我们不需要担心时区的问题。

1
2
3
4
5

public LocalDate convertToLocalDateViaSqlDate(Date dateToConvert) {
    return new java.sql.Date(dateToConvert.getTime()).toLocalDate();
}

将 Date 转换为 LocalDateTime

为了得到一个 LocalDateTime 实例,我们同样可以使用一个中间的 ZonedDateTime,然后使用 toLocalDateTime() API。

就像以前一样,我们可以使用两种可能的解决方案来从java.util.Date中获得一个即时对象。

1
2
3
4
5
6
7
8
9
10
11
12
13

public LocalDateTime convertToLocalDateTimeViaInstant(Date dateToConvert) {
    return dateToConvert.toInstant()
      .atZone(ZoneId.systemDefault())
      .toLocalDateTime();
}

public LocalDateTime convertToLocalDateTimeViaMilisecond(Date dateToConvert) {
    return Instant.ofEpochMilli(dateToConvert.getTime())
      .atZone(ZoneId.systemDefault())
      .toLocalDateTime();
}

从Java 8开始,我们也可以使用java.sql.Timestamp来获得一个LocalDateTime。

1
2
3
4
public LocalDateTime convertToLocalDateTimeViaSqlTimestamp(Date dateToConvert) {
    return new java.sql.Timestamp(
      dateToConvert.getTime()).toLocalDateTime();
}

将 LocalDate转换为 Date

现在我们已经很好地理解了如何从旧的数据表示法转换为新的数据表示法,让我们来看看另一个方向的转换。

我们将讨论将LocalDate转换为Date的两种可能方式。

第一种,我们使用java.sql.Date对象中提供的一个新的valueOf(LocalDate date)方法,它把LocalDate作为一个参数。

1
2
3
public Date convertToDateViaSqlDate(LocalDate dateToConvert) {
    return java.sql.Date.valueOf(dateToConvert);
}

正如我们所看到的,它毫不费力,而且很直观。它使用本地时区进行转换(所有的工作都在引擎盖下完成,所以不用担心)。

在另一个Java 8的例子中,我们使用一个Instant对象,并将其传递给java.util.Date对象的from(Instant instant)方法。

1
2
3
4
5
public Date convertToDateViaInstant(LocalDate dateToConvert) {
    return java.util.Date.from(dateToConvert.atStartOfDay()
      .atZone(ZoneId.systemDefault())
      .toInstant());
}

注意我们在这里使用了一个即时对象,而且在做这个转换时我们还需要关心时区。

接下来,让我们使用一个非常类似的解决方案,将LocalDateTime转换为Date对象。

将java.time.LocalDateTime转换为java.util.Date

从 LocalDateTime 获得java.util.Date的最简单方法是使用java.sql.Timestamp的扩展–在Java 8中可用。

1
2
3
public Date convertToDateViaSqlTimestamp(LocalDateTime dateToConvert) {
    return java.sql.Timestamp.valueOf(dateToConvert);
}

但当然,另一个解决方案是使用一个 Instant 对象,我们从ZonedDateTime中获得这个对象。

1
2
3
4
5
Date convertToDateViaInstant(LocalDateTime dateToConvert) {
    return java.util.Date
      .from(dateToConvert.atZone(ZoneId.systemDefault())
      .toInstant());
}

Java 9的新增功能

在 Java 9 中,有一些新方法可以简化java.util.Date和java.time.LocalDate或java.time.LocalDateTime之间的转换。

LocalDate.ofInstant(Instant instant, ZoneId zone) 和 LocalDateTime.ofInstant(Instant instant, ZoneId zone) 提供了方便的快捷方式。

1
2
3
4
5
6
7
8
9
public LocalDate convertToLocalDate(Date dateToConvert) {
    return LocalDate.ofInstant(
      dateToConvert.toInstant(), ZoneId.systemDefault());
}

public LocalDateTime convertToLocalDateTime(Date dateToConvert) {
    return LocalDateTime.ofInstant(
      dateToConvert.toInstant(), ZoneId.systemDefault());
}

总结

在这篇文章中,指北君介绍了将旧的java.util.Date转换为新的java.time.LocalDate和java.time.LocalDateTime的方式方法。

Java Geek Tech wechat
欢迎订阅 Java 技术指北,这里分享关于 Java 的一切。