Java 将java.util.Date转换为java.time.LocalDate

Java 将java.util.Date转换为java.time.LocalDate,用户希望将 java.util.Datejava.util.Calendar 类转换为 java.time 包中相应的类,转换时既可以利用 Instant 类作为中介,也可以使用 java.sql.Datejava.sql.Timestamp 类提供的方法,还可以使用字符串或整数。

Java 将java.util.Date转换为java.time.LocalDate 问题描述

用户希望将 java.util.Datejava.util.Calendar 类转换为 java.time 包中相应的类。

Java 将java.util.Date转换为java.time.LocalDate 解决方案

转换时既可以利用 Instant 类作为中介,也可以使用 java.sql.Datejava.sql.Timestamp 类提供的方法,还可以使用字符串或整数。

Java 将java.util.Date转换为java.time.LocalDate 具体实例

新的 java.time 包并未提供太多的内置方式来转换 java.util 包中用于处理标准日期和时间的类,这点或许会让读者感到讶异。
为了将 java.util.Date 类转换为 java.time.LocalDate 类,一种方案是调用 toInstant 方法来创建 Instant,然后应用系统默认时区(ZoneId),并从生成的 ZonedDateTime 中提取出 LocalDate,如例 8-18 所示。

例 8-18 利用 Instant 作为中介,将 java.util.Date 类转换为 java.time.LocalDate

public LocalDate convertFromUtilDateUsingInstant(Date date) {
    return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
}

java.util.Date 类包含日期和时间信息,但并不提供时区信息 6,因此它相当于 java.time.Instant 类。将 atZone 方法应用到系统默认时区将创建 ZonedDateTime,之后就能从中提取出 LocalDate
6打印 java.util.Date 时,字符串采用 Java 默认的时区进行格式化。

此外,借由 java.sql.Datejava.sql.Timestamp 类定义的一些方法,也可以方便地将 java.util.Date 类转换为 java.time.LocalDate 类,相关示例请参见例 8-19 和例 8-20。

例 8-19 java.sql.Date 类中的转换方法

LocalDate   toLocalDate()
static Date valueOf(LocalDate date)

例 8-20 java.sql.Timestamp 类中的转换方法

LocalDateTime    toLocalDateTime()
static Timestamp valueOf(LocalDateTime dateTime)

如例 8-21 所示,我们创建一个名为 ConvertDate 的类,从而方便地实现转换。

例 8-21 将 java.util 包中的类转换为 java.time 包中相应的类

package datetime;

import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

public class ConvertDate {
    public LocalDate convertFromSqlDatetoLD(java.sql.Date sqlDate) {
        return sqlDate.toLocalDate();
    }

    public java.sql.Date convertToSqlDateFromLD(LocalDate localDate) {
        return java.sql.Date.valueOf(localDate);
    }

    public LocalDateTime convertFromTimestampToLDT(Timestamp timestamp) {
        return timestamp.toLocalDateTime();
    }

    public Timestamp convertToTimestampFromLDT(LocalDateTime localDateTime) {
        return Timestamp.valueOf(localDateTime);
    }
}

既然所需的方法基于 java.sql.Date 类,那么如何转换 java.util.Date(大部分开发人员仍在使用)以及 java.sql.Date 类呢?一种方案是利用 java.sql.Date 类提供的构造函数,根据给定的毫秒时间值创建一个 Date 对象(long 型数据)。

纪元时间与 Java
在基于 Unix 的操作系统中,Unix 纪元时间(Unix epoch)也称为 Unix 时间戳(Unix timestamp)或 POSIX 时间(POSIX time),定义为从 1970 年 1 月 1 日 00:00:00 UTC 起经过的秒数,不考虑闰秒。目前,计算机的系统时钟均以纪元时间为基础。
需要注意的是,由于 Unix 纪元时间采用 32 位有符号整数存储经过的秒数,将在 2038 年 1 月19 日03:14:07 UTC 时溢出。在这一刻之后,全球所有 32 位操作系统的时间将突然跳回 1901 年 12 月 13 日。这就是所谓的“2038 年问题”(Year 2038 Problem)7。尽管到那个时候,所有操作系统应该都已升级为 64 位,但可能仍有部分嵌入式系统尚未更新8
Java 采用毫秒作为经过时间的单位,这或许会让情况变得更加糟糕。不过使用 long 而非 int 存储经过时间,可以将溢出问题推后数千年。

7参见维基百科的详细介绍。(32 位有符号整数的最大值为 0x7FFFFFFF,即 2^31 – 1= 2147483647 秒,也就是 2038 年 1 月 19 日 03:14:07 UTC。可以通过 Epoch Converter 方便地将 Unix 纪元时间转换为人类可读的格式。——译者注)

8作者届时想必已安全退休,不过当 2038 年问题发生时,希望作者使用的呼吸机不会受到影响。

java.util.Date 类定义了一个返回 long 型数据的 getTime 方法,而 java.sql.Date 类定义了一个传入该 long 值作为参数的构造函数 setTime9
9事实上,setTimejava.sql.Date 类中唯一一个未被弃用的构造函数,可以利用该方法来设置现有的 Date 对象。

因此,借由 java.sql.Date 类,也可以将 java.util.Date 实例转换为 java.time.LocalDate 实例,如例 8-22 所示。

例 8-22 将 java.util.Date 类转换为 java.time.LocalDate

public LocalDate convertUtilDateToLocalDate(java.util.Date date) {
    return new java.sql.Date(date.getTime()).toLocalDate();
}

实际上,早在 Java 1.1 发布时,整个 java.util.Date 类就已被弃用,并推荐采用 java.util.Calendar 类作为替代。Calendar 实例与 java.time 包中相应实例之间的转换可以通过 toInstant 方法完成,并根据时区进行调整,如例 8-23 所示。

例 8-23 将 java.util.Calendar 类转换为 java.time. ZonedDateTime

public ZonedDateTime convertFromCalendar(Calendar cal) {
    return ZonedDateTime.ofInstant(cal.toInstant(), cal.getTimeZone().toZoneId());
}

上述方法使用 ZonedDateTime 类。LocalDateTime 类也定义了一个名为 ofInstant 的方法,不过由于某种原因,该方法传入 ZoneId 作为第二个参数。因为 LocalDateTime 类并不包含时区信息,这显得颇为奇怪。有鉴于此,改用 ZonedDateTime 类定义的 ofInstant 方法或许更加直观。
如果完全不必考虑时区信息,也可以在 Calendar 类上显式地使用各种 getter 方法,直接转换为相应的 LocalDateTime,如例 8-24 所示。

例 8-24 利用 getter 方法将 java.util.Calendar 转换为 java.time.LocalDateTime

public LocalDateTime convertFromCalendarUsingGetters(Calendar cal) {
    return LocalDateTime.of(cal.get(Calendar.YEAR),
        cal.get(Calendar.MONTH),
        cal.get(Calendar.DAY_OF_MONTH),
        cal.get(Calendar.HOUR),
        cal.get(Calendar.MINUTE),
        cal.get(Calendar.SECOND));
}

另一种方案是根据 Calendar 类生成一个经过格式化的字符串,然后将其解析为 LocalDateTime,如例 8-25 所示。

例 8-25 生成并解析时间戳字符串

public LocalDateTime convertFromUtilDateToLDUsingString(Date date) {
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    return LocalDateTime.parse(df.format(date),
        DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}

上述方案并非特别理想,不过了解它并无坏处。此外,Calendar 类并未提供能直接转换为 ZonedDateTime 的方法,但 GregorianCalendar 类定义的 toZonedDateTime 方法可以实现这种转换,如例 8-26 所示。

例 8-26 将 java.util.GregorianCalendar 类转换为 java.time.ZonedDateTime

public ZonedDateTime convertFromGregorianCalendar(Calendar cal) {
    return ((GregorianCalendar) cal).toZonedDateTime();
}

上述程序可以执行,不过前提是采用公历(Gregorian calendar)。由于 GregorianCalendar 类是 Calendar 类的唯一实现,这种前提应该成立,但无法百分之百确定。
最后,Java 9 为 LocalDate 类引入了 ofInstant 方法,使得转换操作更为简单,如例 8-27 所示。

例 8-27 将 java.util.Date 类转换为 java.time.LocalDate 类(仅针对 Java 9)

public LocalDate convertFromUtilDateJava9(Date date) {
    return LocalDate.ofInstant(date.toInstant(), ZoneId.systemDefault());
}

这种方案更直接,但仅能在 Java 9 中使用。

赞(0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

Java 实例