旧版日期时间代码
在 Java SE 8 版本之前,Java 日期和时间机制由 java.util.Date
、java.util.Calendar
和 java.util.TimeZone
类及其子类(如 java.util.GregorianCalendar
)提供。这些类存在一些缺点,包括
Calendar
类不是类型安全的。- 由于这些类是可变的,因此不能在多线程应用程序中使用它们。
- 由于月份编号不寻常以及缺乏类型安全性,应用程序代码中的错误很常见。
与旧版代码的互操作性
也许您有使用 java.util
日期和时间类的旧版代码,并且您希望利用 java.time
功能,同时对代码进行最少的更改。
JDK 8 版本中添加了一些方法,允许在 java.util
和 java.time
对象之间进行转换
Calendar.toInstant()
将Calendar
对象转换为Instant
。GregorianCalendar.toZonedDateTime()
将GregorianCalendar
实例转换为ZonedDateTime
。GregorianCalendar.from(ZonedDateTime)
使用默认区域设置从ZonedDateTime
实例创建一个GregorianCalendar
对象。Date.from(Instant)
从Instant
创建一个Date
对象。Date.toInstant()
将Date
对象转换为Instant
。TimeZone.toZoneId()
将TimeZone
对象转换为ZoneId
。
以下示例将 Calendar
实例转换为 ZonedDateTime
实例。请注意,必须提供时区才能从 Instant
转换为 ZonedDateTime
Calendar now = Calendar.getInstance();
ZonedDateTime zdt = ZonedDateTime.ofInstant(now.toInstant(), ZoneId.systemDefault()));
以下示例显示了 Date 和 Instant 之间的转换
Instant inst = date.toInstant();
Date newDate = Date.from(inst);
以下示例从 GregorianCalendar 转换为 ZonedDateTime,然后从 ZonedDateTime 转换为 GregorianCalendar。其他基于时间的类是使用 ZonedDateTime 实例创建的
GregorianCalendar cal = ...;
TimeZone tz = cal.getTimeZone();
int tzoffset = cal.get(Calendar.ZONE_OFFSET);
ZonedDateTime zdt = cal.toZonedDateTime();
GregorianCalendar newCal = GregorianCalendar.from(zdt);
LocalDateTime ldt = zdt.toLocalDateTime();
LocalDate date = zdt.toLocalDate();
LocalTime time = zdt.toLocalTime();
将旧版日期和时间功能映射到日期时间 API
由于 Java 中的日期和时间实现已在 Java SE 8 版本中完全重新设计,因此您无法将一种方法替换为另一种方法。如果您想使用 java.time
包提供的丰富功能,最简单的解决方案是使用上一节中列出的 toInstant()
或 toZonedDateTime()
方法。但是,如果您不想使用这种方法,或者它不足以满足您的需求,那么您必须重写日期时间代码。
在 概述 页面上介绍的 表格 是一个很好的起点,可以评估哪些 java.time
类满足您的需求。
这两个 API 之间没有一对一的映射对应关系,但下表让您大致了解 java.util
日期和时间类中的哪些功能映射到 java.time
API。
旧版 Date 和 Instant 之间的对应关系
- 表示时间轴上的一个瞬时时间点(UTC)
- 保存与时区无关的时间
- 表示为纪元秒(自 1970-01-01T00:00:00Z 以来)加上纳秒
Date.from(Instant)
和 Date.toInstant()
方法允许在这些类之间进行转换。
GregorianCalendar 和 ZonedDateTime 之间的对应关系
ZonedDateTime
类是 GregorianCalendar
的替代品。它提供了以下类似的功能。人类时间表示如下
LocalDate
:年、月、日LocalTime
:时、分、秒、纳秒ZoneId
:时区ZoneOffset
:当前与 GMT 的偏移量
GregorianCalendar.from(ZonedDateTime)
和 GregorianCalendar.toZonedDateTime()
方法便于在这些类之间进行转换。
旧版 TimeZone 和 ZoneId 或 ZoneOffset 之间的对应关系
ZoneId
类指定一个时区标识符,并可以访问每个时区使用的规则。 ZoneOffset
类仅指定与格林威治/UTC 的偏移量。有关更多信息,请参见 时区和偏移量类。
日期设置为 1970-01-01 的 GregorianCalendar 与 LocalTime 之间的对应关系
将日期设置为 1970-01-01 的 GregorianCalendar
实例以使用时间组件的代码可以替换为 LocalTime
的实例。
时间设置为 00:00 的 GregorianCalendar 与 LocalDate 之间的对应关系
将时间设置为 00:00 的 GregorianCalendar
实例以使用日期组件的代码可以替换为 LocalDate
的实例。(这种 GregorianCalendar
方法存在缺陷,因为由于夏令时的转换,一些国家/地区每年都会出现午夜。)
日期和时间格式化
尽管java.time.format.DateTimeFormatter
提供了强大的日期和时间值格式化机制,但您也可以直接使用java.time
基于时间类的java.util.Formatter
和String.format()
,使用与java.util
日期和时间类相同的基于模式的格式化。
上次更新: 2022 年 1 月 27 日