介绍
在我们的这个世界上因为地球是圆的,所以每个国家都会有自己特定的时区。
时区在我们对时间的使用上扮演了非常重要的角色。但又因为时区的存在,又给我们带来了很多的麻烦,比如北美地区使用的夏令时和中国统一使用东 8 区的时间等。
当这些时间在我们计算机中进行体现的时候就会给我们带来不少的麻烦,为了解决这些麻烦,Java 提供了一些 API 来进行处理,比如用到的 Date,Time 和 DateTime。
我们都知道,Java 的时间处理因为 API 的使用会变得非常的繁琐,所以在新的版本 Java 中,Java 尝试解决这个问题,为此开始提供 ZoneId 和 ZoneOffset API 来管理时区。
在本文中,我们将会对 ZoneId 和ZoneOffset 进行一些探讨,同时也对 DateTime 类进行一些探索。
ZoneId 和 ZoneOffset
在 JSR-310 发布的版本中,Java 添加了一些 API 用来管理日期,时间和有时区的时间。
ZoneId 和 ZoneOffset 类做为上面更新的一部分也同时添加到了 Java 中。
ZoneId
*ZoneId 在 Java 中被用来表示时区,例如 ‘Europe/Paris‘.
针对 ZoneId 有 2 个实现,第一个实现是针对 GMT/UTC 来计算偏移量。
第二个实现为使用距离的地理区域,这会针对 GMT/UTC 对比来进行一系列的计算。
让我们来创建一个 Berlin, Germany 的 ZoneId 实例。
ZoneId zone = ZoneId.of("Europe/Berlin");
针对中国可以使用的时间定义为标准北京时间。
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
但使用的时间字符串为上海。
ZoneOffset
ZoneOffset 集成了 ZoneId 同时来定义了当前使用的时区针对 GMT/UTC 的偏移量,例如:+02:00。
这就意味这个这个数字表示的是针对 UTC 标准时间使用的固定小时和分钟数。
LocalDateTime now = LocalDateTime.now();ZoneId zone = ZoneId.of("Asia/Shanghai");ZoneOffset zoneOffSet = zone.getRules().getOffset(now);logger.debug("zoneOffSet: {}", zoneOffSet);
上面代码的输出为:
09:13:25.045 [main] DEBUG com.ossez.datetime.DateTimeZoneUnitTest - zoneOffSet: +08:00
因为北京使用的是东八区的时间。
针对同一个国家可能有 2 个针对 UTC 时间的偏移量——这些国家主要是使用夏令时的国家。比如说美国就是一个使用夏令时的国家。
因此,针对这些国家 ZoneOffset 就会有 2 个实现了,具体需要参考 LocalDateTime* API 中的实现。
DateTime 类
下一个,让我们来讨论下 DateTime 类,这个类实际上将会使用 ZoneId 和 ZoneOffset。
ZonedDateTime
ZonedDateTime 是不可变(immutable )的实现,这个用来输出一个基于 ISO-8601 表达方式的时间。
例如: 2007-12-03T10:15:30+01:00 Europe/Pari。
一个 ZonedDateTime 将会表达有 3 个部分,分别为LocalDateTime, ZoneId 和 ZoneOffset。
这个类将会保存有所有的日期和时间字段来精确的表达时间,时区和时区偏移量。
我们用这个来处理模糊的本地时间。
例如:, ZonedDateTime 可以保存值 “2nd October 2007 at 13:45.30.123456789 +02:00 in the Europe/Paris time-zone”。
让我们使用 ZonedDateTime 来显示当前的时间。
@Testpublic void ZonedDateTime_out() {ZoneId zone = ZoneId.of("Asia/Shanghai");ZonedDateTime date = ZonedDateTime.now(zone);logger.debug("date: {}", date);}
上面程序的输出为:
09:32:04.549 [main] DEBUG com.ossez.datetime.DateTimeZoneUnitTest - date: 2025-01-16T22:32:04.547368100+08:00[Asia/Shanghai]
从实例化的输出来看,保留了非常多的时间信息。
我的计算机是现在东部时间,可以看到获得的实例已经转换成了北京时间。
ZonedDateTime 同时还提供了内置函数来从一个时区转换为另外的一个时区。
ZonedDateTime destDate = sourceDate.withZoneSameInstant(destZoneId);
OffsetDateTime
OffsetDateTime 是不可变的的一个日期时间,这个日期时间使用的是针对 UTC 的偏移量来进行保存的,同样使用 ISO-8601 格式。
例如:2007-12-03T10:15:30+01:00.
这个类将会保存有所有的日期和时间字段来精确的表达时间,时区和时区偏移量。
例如:OffsetDateTime 可以寸尺值 “2nd October 2007 at 13:45.30.123456789 +02:00”。
让我们来获得针对 GMT/UTC 2 小时偏移量的 OffsetDateTime :
ZoneOffset zoneOffSet= ZoneOffset.of("+02:00");
OffsetDateTime date = OffsetDateTime.now(zoneOffSet);
OffsetTime
OffsetTime 是不可变的的一个时间。
通常这个时间使用 hour-minute-second-offset 来进行表达,在 ISO-8601 日历系统中将会输出为:: 10:15:30+01:00。
这个类只会存储时间,不会对日期进行存储。
可以使用 “13:45.30.123456789+02:00” 来对其初始化。
让我们来获得 OffsetTime 2 个时区的偏离量:
ZoneOffset zoneOffSet = ZoneOffset.of("+02:00");
OffsetTime time = OffsetTime.now(zoneOffSet);
结论
ZoneOffset 通常用来处理针对 GMT/UTC 不同时区的偏移量。
同时 ZoneId 和 ZoneOffset 不会单独使用,通常会结合 DateTime 的时间类来使用。
例如 Java 中使用的 ZonedDateTime, OffsetDateTime, 和 OffsetTime。
https://www.isharkfly.com/t/java-zoneoffset/16803