1. 概述
Java的LocalDateTime
API用于表示和操作日期和时间的组合。ZonedDateTime
是一个不可变对象,它包含纳秒级的时间戳、基于ISO 8601日历系统的时间区信息,以及处理模糊本地时间的ZoneOffset
。
在这个教程中,我们将了解如何将LocalDateTime
转换为ZonedDateTime
,反之亦然。
2. 将LocalDateTime
转换为ZonedDateTime
2.1. 使用atZone()
方法
LocalDateTime
实例的atZone()
方法执行到ZonedDateTime
的转换,并保持相同的时间日期值:
LocalDateTime localDateTime = LocalDateTime.of(2022, 1, 1, 0, 30, 22);
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Canada/Atlantic"));
assertEquals(localDateTime.getYear(), zonedDateTime.getYear());
assertEquals(localDateTime.getMonth(), zonedDateTime.getMonth());
assertEquals(localDateTime.getDayOfMonth(), zonedDateTime.getDayOfMonth());
assertEquals(localDateTime.getHour(), zonedDateTime.getHour());
assertEquals(localDateTime.getMinute(), zonedDateTime.getMinute());
assertEquals(localDateTime.getSecond(), zonedDateTime.getSecond());
atZone()
方法接收一个ZoneId
值,该值根据ISO 8601日历系统指定时区。
调用withZoneSameInstant()
方法使用ZoneOffSet
时间差来转换实际的时间日期值:
LocalDateTime localDateTime = LocalDateTime.of(2022, 1, 1, 0, 30, 22);
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Africa/Lagos")).withZoneSameInstant(ZoneId.of("Canada/Atlantic"));
assertEquals("2021-12-31T19:30:22-04:00[Canada/Atlantic]", zonedDateTime.toString());
assertEquals("-04:00", zonedDateTime.getOffset().toString());
我们可以通过调用静态ZoneId.getAvailableZoneIds()
方法获取可用的ZoneId
集合,该方法返回所有可用的基于区域的ID字符串,我们可以从中选择创建ZoneId
对象。
此外,使用atZone()
转换还会附带一个ZoneOffSet
值,它提供了ZonedDateTime
对象与UTC(格林尼治标准时间)之间的时差(如上述示例中的-04:00
)。
2.2. 使用ZonedDateTime.of()
方法
ZonedDateTime
类还提供了一个静态of()
方法来创建ZonedDateTime
对象。该方法接受LocalDateTime
和ZoneId
实例作为参数,返回一个ZonedDateTime
对象:
LocalDateTime localDateTime = LocalDateTime.of(2022, 11, 5, 7, 30, 22);
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("Africa/Accra")).withZoneSameInstant(ZoneId.of("Africa/Lagos"));
assertEquals("2022-11-05T08:30:22+01:00[Africa/Lagos]", zonedDateTime.toString());
assertEquals(localDateTime.getYear(), zonedDateTime.getYear());
同样,如前所见,我们可以通过调用withZoneSameInstant()
方法获取给定时区的实际时间日期值。
2.3. 使用ZonedDateTime.ofInstant()
方法
我们还可以使用ZoneOffSet
对象与LocalDateTime
一起创建ZonedDateTime
对象。
静态ofInstant()
方法接受LocalDateTime
、ZoneOffSet
和ZoneId
对象作为参数:
LocalDateTime localDateTime = LocalDateTime.of(2022, 1, 5, 17, 30, 22);
ZoneId zoneId = ZoneId.of("Africa/Lagos");
ZoneOffset zoneOffset = zoneId.getRules().getOffset(localDateTime);
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(localDateTime, zoneOffset, zoneId);
assertEquals("2022-01-05T17:30:22+01:00[Africa/Lagos]", zonedDateTime.toString());
ZonedDateTime
对象是隐式由LocalDateTime
和ZoneOffSet
对象结合形成的Instant
对象创建的。
2.4. 使用ZonedDateTime.ofLocal()
方法
静态ofLocal()
方法从传递给它的首选ZoneOffSet
对象的LocalDateTime
对象创建ZonedDateTime
:
LocalDateTime localDateTime = LocalDateTime.of(2022, 8 , 25, 8, 35, 22);
ZoneId zoneId = ZoneId.of("Africa/Lagos");
ZoneOffset zoneOffset = zoneId.getRules().getOffset(localDateTime);
ZonedDateTime zonedDateTime = ZonedDateTime.ofLocal(localDateTime, zoneId, zoneOffset);
assertEquals("2022-08-25T08:35:22+01:00[Africa/Lagos]", zonedDateTime.toString());
通常情况下,对于本地日期时间,只存在一个有效偏移量。当时间重叠发生时,将有两个有效的偏移量。
如果传递给ofLocal()
方法的首选ZoneOffset
是有效偏移量之一,则使用它。否则,转换会保持之前的有效偏移量。
2.5. 使用ZonedDateTime.ofStrict()
方法
类似地,静态ofStrict()
方法通过严格验证LocalDateTime
、ZoneOffSet
和ZoneID
参数组合,返回一个ZonedDateTime
对象:
LocalDateTime localDateTime = LocalDateTime.of(2022, 12, 25, 6, 18, 2);
ZoneId zoneId = ZoneId.of("Asia/Tokyo");
ZoneOffset zoneOffset = zoneId.getRules().getOffset(localDateTime);
ZonedDateTime zonedDateTime = ZonedDateTime.ofStrict(localDateTime, zoneOffset, zoneId);
assertEquals("2002-12-25T06:18:02+09:00[Asia/Tokyo]", zonedDateTime.toString());
如果提供无效的参数组合,该方法将抛出DateTimeException
:
zoneId = ZoneId.of("Asia/Tokyo");
zoneOffset = ZoneOffset.UTC;
assertThrows(DateTimeException.class, () -> ZonedDateTime.ofStrict(localDateTime, zoneOffset, zoneId));
上述示例显示,当我们尝试使用代表默认UTC(格林尼治标准时间+0)的ZoneId
值和ZoneOffSet
值创建ZonedDateTime
对象时,会抛出异常。
3. 将ZonedDateTime
转换为LocalDateTime
ZonedDateTime
对象维护三个独立的对象:LocalDateTime
、ZoneId
和ZoneOffset
。
我们可以使用toLocalDateTime()
方法将ZonedDateTime
实例转换为LocalDateTime
:
ZonedDateTime zonedDateTime = ZonedDateTime.of(2011, 2, 12, 6, 14, 1, 58086000, ZoneId.of("Asia/Tokyo"));
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
assertEquals("2011-02-12T06:14:01.058086+09:00[Asia/Tokyo]", zonedDateTime.toString());
此方法从ZonedDateTime
属性中检索存储的LocalDateTime
对象。
4. 总结
在本文中,我们学习了如何在Java中将LocalDateTime
转换为ZonedDateTime
以及反过来。
如往常一样,示例代码可以在GitHub上找到:GitHub链接。