1. 概述

在Java中处理日期时,我们常常会遇到以long值表示的日期/时间,这些值表示自纪元(1970年1月1日格林尼治标准时间00:00:00)以来的天数、秒数或毫秒数。

在这个简短的教程中,我们将探讨将long值转换为Java中的日期的不同方法。首先,我们将解释如何使用核心JDK类来实现这一目标。然后,我们将展示如何使用第三方Joda-Time库来达到相同的目标。

2. 使用Java 8+日期时间API

Java 8因其引入的新日期时间API功能而备受赞誉。这个API主要是为了弥补旧日期API的不足。接下来,让我们仔细看看这个API提供了什么,以回答我们的核心问题。

2.1. 使用Instant

最简单的解决方案是使用Java 8新日期时间API中引入的Instant类。这个类描述了时间线上的一个单一瞬时点

让我们实践一下:

@Test
void givenLongValue_whenUsingInstantClass_thenConvert() {
    Instant expectedDate = Instant.parse("2020-09-08T12:16:40Z");
    long seconds = 1599567400L;

    Instant date = Instant.ofEpochSecond(seconds);

    assertEquals(expectedDate, date);
}

如上所示,我们使用ofEpochSecond()方法创建了一个Instant类的对象。请注意,我们也可以使用ofEpochMilli()方法,使用毫秒来创建Instant实例。

2.2. 使用LocalDate

当你需要将long值转换为日期时,LocalDate类是另一个可考虑的选择。这个类表示经典的日期,例如2023-10-17,不包含时间细节。

通常,我们可以使用LocalDate#ofEpochDay方法来实现目标:

@Test
void givenLongValue_whenUsingLocalDateClass_thenConvert() {
    LocalDate expectedDate = LocalDate.of(2023, 10, 17);
    long epochDay = 19647L;

    LocalDate date = LocalDate.ofEpochDay(epochDay);

    assertEquals(expectedDate, date);
}

ofEpochDay()方法根据给定的历元日创建LocalDate类的实例。

3. 使用遗留的日期API

在Java 8之前,我们通常会使用java.util包中的DateCalendar类来达成目标。现在让我们看看如何使用这两个类将long值转换为日期。

3.1. 使用Date

Date类表示具有毫秒精度的具体时间点。顾名思义,它提供了一系列方法,可以用来操作日期。它提供了将long值转换为日期的最简单方式,因为它有一个接受long类型参数的重载构造函数

让我们演示一下:

@Test
void givenLongValue_whenUsingDateClass_thenConvert() {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date expectedDate = dateFormat.parse("2023-10-15 22:00:00");
    long milliseconds = 1689458400000L;

    Date date = new Date(milliseconds);

    assertEquals(expectedDate, date);
}

请注意,Date类已过时,属于旧API,因此在处理日期时不是最佳选择。

3.2. 使用Calendar

另一种解决方案是使用旧日期API中的Calendar类。这个类提供了setTimeInMillis(long value)方法,我们可以用它来将时间设置为给定的long

现在,让我们用另一个测试案例来说明这个方法的用法:

@Test
void givenLongValue_whenUsingCalendarClass_thenConvert() {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date expectedDate = dateFormat.parse("2023-07-15 22:00:00");
    long milliseconds = 1689458400000L;

    Calendar calendar = Calendar.getInstance();
    calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
    calendar.setTimeInMillis(milliseconds);

    assertEquals(expectedDate, calendar.getTime());
}

同样,指定的long值表示自纪元以来经过的毫秒数。

4. 使用Joda-Time

最后,我们可以使用Joda-Time库来解决这个问题。首先,我们需要将其依赖项添加到pom.xml文件中:

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.12.5</version>
</dependency>

Joda-Time也提供了其版本的LocalDate类。接下来,我们将看到如何使用它将long值转换为LocalDate对象:

@Test
void givenLongValue_whenUsingJodaTimeLocalDateClass_thenConvert() {
    org.joda.time.LocalDate expectedDate = new org.joda.time.LocalDate(2023, 7, 15);
    long milliseconds = 1689458400000L;

    org.joda.time.LocalDate date = new org.joda.time.LocalDate(milliseconds, DateTimeZone.UTC);

    assertEquals(expectedDate, date);
}

如图所示,LocalDate提供了直接从long值构建日期的方法。

5. 总结

在这篇简短的文章中,我们详细解释了如何在Java中将long值转换为日期。

首先,我们展示了如何使用内置的JDK类进行转换。然后,我们展示了如何使用Joda-Time库来实现相同的目标。

本文中的所有代码可以在GitHub上找到。