1. 引言

在我们生活的世界中,每个国家都会遵循特定的时区(time-zone)。这些时区对于准确、方便地表达时间至关重要。然而,由于夏令时等因素的影响,时区有时会变得不那么明确。

在代码中表示这些时区时也容易产生混淆。Java 在过去提供了诸如 DateTimeDateTime 等类来处理时区问题。

随着 Java 版本的演进,引入了更加实用且表达力更强的新类,如 ZoneIdZoneOffset,用于更精细地管理时区信息。

本文将重点讨论 ZoneIdZoneOffset 以及相关的日期时间类

如果你对 Java 8 新引入的日期时间 API 还不太熟悉,可以先阅读我们之前的介绍文章:Java 8 日期时间 API 入门

2. ZoneIdZoneOffset

随着 JSR-310 的引入,Java 提供了一系列强大的 API 来处理日期、时间和时区。其中就包括 ZoneIdZoneOffset 类。

2.1. ZoneId

正如前面提到的,**ZoneId 表示一个时区标识符**,例如 "Europe/Paris"

ZoneId 有两种实现方式:

  • 一种是相对于 GMT/UTC 的固定偏移量;
  • 另一种是地理区域,它有一套规则用于计算相对于 GMT/UTC 的偏移量。

举个例子,我们可以创建一个代表德国柏林的 ZoneId

ZoneId zone = ZoneId.of("Europe/Berlin");

2.2. ZoneOffset

ZoneOffset 继承自 ZoneId,表示当前时区相对于 GMT/UTC 的固定偏移量,例如 +02:00

这意味着该数值表示固定的小时和分钟差值,用于描述当前时区与 GMT/UTC 时间之间的差异:

LocalDateTime now = LocalDateTime.now();
ZoneId zone = ZoneId.of("Europe/Berlin");
ZoneOffset zoneOffSet = zone.getRules().getOffset(now);

⚠️ 如果一个国家在夏季和冬季使用不同的偏移量,那么同一地区就会存在两个不同的 ZoneOffset 实现。因此需要传入一个 LocalDateTime 来确定具体使用的偏移量。

3. 使用 ZoneIdZoneOffset 的日期时间类

下面我们将介绍一些实际利用了 ZoneIdZoneOffset 的日期时间类。

3.1. ZonedDateTime

ZonedDateTime 是一个不可变的类,表示 ISO-8601 日历系统中带有时区信息的日期时间,例如:

2007-12-03T10:15:30+01:00 Europe/Paris

ZonedDateTime 内部包含了三个核心组件

  • 一个 LocalDateTime
  • 一个 ZoneId
  • 以及解析后的 ZoneOffset

这个类能够存储纳秒级精度的所有日期和时间字段,并通过 ZoneOffset 处理本地时间的歧义问题。例如它可以存储如下值:

“2007年10月2日 13:45:30.123456789 +02:00 欧洲巴黎时区”

获取当前时区下的 ZonedDateTime 示例:

ZoneId zone = ZoneId.of("Europe/Berlin");
ZonedDateTime date = ZonedDateTime.now(zone);

此外,ZonedDateTime 还提供了便捷方法,用于将某个时间从一个时区转换到另一个时区:

ZonedDateTime destDate = sourceDate.withZoneSameInstant(destZoneId);

3.2. OffsetDateTime

OffsetDateTime 是一个不可变类,表示 ISO-8601 日历系统中带有偏移量的日期时间,例如:

2007-12-03T10:15:30+01:00

此类存储所有日期和时间字段(精度到纳秒),并包含相对于 GMT/UTC 的偏移量

例如它可以存储如下值:

“2007年10月2日 13:45:30.123456789 +02:00”

创建一个比 GMT/UTC 快两个小时的 OffsetDateTime

ZoneOffset zoneOffSet = ZoneOffset.of("+02:00");
OffsetDateTime date = OffsetDateTime.now(zoneOffSet);

3.3. OffsetTime

OffsetTime 是一个不可变类,表示 ISO-8601 日历系统中带有时区偏移的时间,例如:

10:15:30+01:00

此类存储所有时间字段(精度到纳秒)以及对应的时区偏移量

例如它可以存储如下值:

“13:45:30.123456789 +02:00”

创建一个比 GMT/UTC 快两个小时的 OffsetTime

ZoneOffset zoneOffSet = ZoneOffset.of("+02:00");
OffsetTime time = OffsetTime.now(zoneOffSet);

4. 总结

回到重点:**ZoneOffset 是一种基于 GMT/UTC 偏移量来表示时区的方式**。虽然还有其他方式表示时区,但这种方式简单直接,在很多场景下非常实用。

同时,ZoneIdZoneOffset 不仅可以单独使用,也被广泛应用于 Java 的一些日期时间类中,如:

  • ZonedDateTime
  • OffsetDateTime
  • OffsetTime

一如既往,本文所涉及的代码示例均可在我们的 GitHub 仓库中找到: 👉 GitHub 项目地址


原始标题:ZoneOffset in Java | Baeldung