ZoneId 和 ZoneOffset 是 Java 8 处理时区的核心工具,前者适合地理时区(含动态规则,如夏时令),后者适合处理固定偏移量(如 +08:00、-05:00,不包含动态调整规则)。
ZoneId 表示地理时区(如 "Asia/Shanghai"、"Europe/London"),包含时区的规则(如夏令时调整),可动态计算不同时间点的偏移量。
用于获取 JVM 所在系统的默认时区。默认时区由 JVM 启动时的系统设置决定,可通过user.timezone系统属性修改。示例:
package com.hxstrive.java_date_time.zoneId; import java.time.ZoneId; public class ZoneIdDemo { public static void main(String[] args) { ZoneId defaultZone = ZoneId.systemDefault(); System.out.println("系统默认时区:" + defaultZone); // 如 Asia/Shanghai } }
运行结果:
系统默认时区:Asia/Shanghai
根据时区 ID 创建 ZoneId 实例。注意:
(1)时区 ID 需符合规范,主要有两类:
地理区域 ID(推荐):如 "Asia/Shanghai"、"America/New_York"(由 IANA 维护,网址 Internet Assigned Numbers Authority)。
偏移量 ID:如 UTC+08:00(实际会返回 ZoneOffset 实例)。
(2)无效 ID 会抛出 ZoneRulesException 异常。
示例:
// 地理时区ID ZoneId shanghai = ZoneId.of("Asia/Shanghai"); System.out.println(shanghai.getId()); // 输出:Asia/Shanghai // 偏移量ID(返回ZoneOffset) ZoneId utcPlus8 = ZoneId.of("UTC+08:00"); System.out.println(utcPlus8 instanceof ZoneOffset); // 输出:false
获取所有可用的时区 ID(地理区域 ID)。注意,返回结果是一个不可变集合,包含约 600 个时区 ID,因 JVM 版本和系统而异。示例:
import java.time.ZoneId; import java.util.Set; public class ZoneIdDemo2 { public static void main(String[] args) { Set<String> zoneIds = ZoneId.getAvailableZoneIds(); // 打印部分常用时区 zoneIds.stream() .filter(id -> id.startsWith("Asia/") || id.startsWith("Europe/")) .limit(5) .forEach(System.out::println); } }
运行结果:
Asia/Aden Asia/Aqtau Asia/Pontianak Asia/Kuching Europe/London
获取时区的 ID 字符串(如 "Asia/Shanghai")。示例:
ZoneId london = ZoneId.of("Europe/London"); System.out.println(london.getId()); // 输出:Europe/London
获取时区的规则(ZoneRules),包含该时区的偏移量计算逻辑(如夏令时切换)。注意,ZoneRules 可用于查询特定时间点的偏移量。示例:
package com.hxstrive.java_date_time.zoneId; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.zone.ZoneRules; public class ZoneIdDemo3 { public static void main(String[] args) { ZoneId newYork = ZoneId.of("America/New_York"); // 获取纽约时区的规则 ZoneRules rules = newYork.getRules(); // 查询2024年1月1日纽约的偏移量(冬季时间,UTC-5) ZonedDateTime winter = ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, newYork); System.out.println(rules.getOffset(winter.toInstant())); // 输出:-05:00 // 查询2024年7月1日纽约的偏移量(夏令时,UTC-4) ZonedDateTime summer = ZonedDateTime.of(2024, 7, 1, 0, 0, 0, 0, newYork); System.out.println(rules.getOffset(summer.toInstant())); // 输出:-04:00 } }
运行结果:
-05:00 -04:00
ZoneOffset 是 ZoneId 的子类,表示与 UTC 的固定偏移量(如 +08:00、-05:00),不包含夏令时等动态调整规则,适用于固定偏移场景。
表示 UTC 时区(偏移量为 0)的常量。示例:
import java.time.ZoneOffset; public class ZoneOffsetDemo { public static void main(String[] args) { ZoneOffset utc = ZoneOffset.UTC; System.out.println(utc.getTotalSeconds()); // 输出:0 } }
根据偏移量字符串创建 ZoneOffset 实例。注意:
偏移量格式:Z(表示 UTC)、+HH、+HH:MM、+HHMM(如 "Z"、"+08:00"、"-0530")。
偏移范围必须在 - 18:00 到 + 18:00 之间,否则抛出 DateTimeException。
示例:
ZoneOffset offset1 = ZoneOffset.of("+08:00"); // 东8区 ZoneOffset offset2 = ZoneOffset.of("Z"); // UTC(等价于+00:00) ZoneOffset offset3 = ZoneOffset.of("-0330"); // 西3区30分 System.out.println(offset1); // 输出:+08:00 System.out.println(offset2); // 输出:Z System.out.println(offset3); // 输出:-03:30
运行结果:
+08:00 Z -03:30
如果偏移范围超出了 -18:00~+18:00,错误信息如下:
Exception in thread "main" java.time.DateTimeException: Zone offset hours not in valid range: value 19 is not in the range -18 to 18 at java.base/java.time.ZoneOffset.validate(ZoneOffset.java:373) at java.base/java.time.ZoneOffset.ofHoursMinutesSeconds(ZoneOffset.java:326) at java.base/java.time.ZoneOffset.of(ZoneOffset.java:259)
根据小时数创建 ZoneOffset(精确到小时),小时范围为 - 18 到 + 18,超出抛出异常。示例:
ZoneOffset offset = ZoneOffset.ofHours(9); // 东9区(如东京) System.out.println(offset); // 输出:+09:00
根据小时和分钟创建 ZoneOffset(精确到分钟)。注意:
总偏移量(小时 ×60 + 分钟)范围为 -1080 到 +1080 分钟(即 -18 到 +18 小时)。
分钟需与小时符号一致(如小时为正,分钟不能为负)。
示例:
ZoneOffset offset = ZoneOffset.ofHoursMinutes(3, 30); // +03:30 System.out.println(offset); // 输出:+03:30
获取偏移量的总秒数(方便计算)。示例:
ZoneOffset offset = ZoneOffset.of("+08:00"); System.out.println(offset.getTotalSeconds()); // 输出:28800(8×3600)
特性 | ZoneId | ZoneOffset |
含义 | 地理时区(含动态规则) | 与 UTC 的固定偏移量 |
适用场景 | 需要考虑夏令时、区域规则的场景 | 固定偏移(如日志、协议格式) |
动态性 | 偏移量随时间可能变化(夏令时) | 偏移量固定不变 |
示例 | Asia/Shanghai 表示上海 | +08:00 或 Z |
两者的选用原则:
若需表示某个地区的真实时区(如用户所在城市),用ZoneId(自动处理夏令时)。
若只需固定偏移(如网络协议中的时间格式),用ZoneOffset。