ZoneId 与 ZoneOffset(时区和偏移量)

ZoneId 和 ZoneOffset 是 Java 8 处理时区的核心工具,前者适合地理时区(含动态规则,如夏时令),后者适合处理固定偏移量(如 +08:00、-05:00,不包含动态调整规则)。

  

ZoneId 类

ZoneId 表示地理时区(如 "Asia/Shanghai"、"Europe/London"),包含时区的规则(如夏令时调整),可动态计算不同时间点的偏移量。

常用方法及示例

systemDefault()

用于获取 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

of(String zoneId)

根据时区 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

getAvailableZoneIds()

获取所有可用的时区 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

getId()

获取时区的 ID 字符串(如 "Asia/Shanghai")。示例:

ZoneId london = ZoneId.of("Europe/London");
System.out.println(london.getId()); // 输出:Europe/London

getRules()

获取时区的规则(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 类

ZoneOffset 是 ZoneId 的子类,表示与 UTC 的固定偏移量(如 +08:00、-05:00),不包含夏令时等动态调整规则,适用于固定偏移场景。

ZoneId 与 ZoneOffset

常用方法及示例

UTC

表示 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
    }
}

of(String offsetId)

根据偏移量字符串创建 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)

ofHours(int hours)

根据小时数创建 ZoneOffset(精确到小时),小时范围为 - 18 到 + 18,超出抛出异常。示例:

ZoneOffset offset = ZoneOffset.ofHours(9); // 东9区(如东京)
System.out.println(offset); // 输出:+09:00

ofHoursMinutes(int hours, int minutes)

根据小时和分钟创建 ZoneOffset(精确到分钟)。注意:

  • 总偏移量(小时 ×60 + 分钟)范围为 -1080 到 +1080 分钟(即 -18 到 +18 小时)。

  • 分钟需与小时符号一致(如小时为正,分钟不能为负)。

示例:

ZoneOffset offset = ZoneOffset.ofHoursMinutes(3, 30); // +03:30
System.out.println(offset); // 输出:+03:30

getTotalSeconds()

获取偏移量的总秒数(方便计算)。示例:

ZoneOffset offset = ZoneOffset.of("+08:00");
System.out.println(offset.getTotalSeconds()); // 输出:28800(8×3600)

  

ZoneId 与 ZoneOffset 的区别与选用

特性

ZoneId

ZoneOffset

含义

地理时区(含动态规则)

与 UTC 的固定偏移量

适用场景

需要考虑夏令时、区域规则的场景

固定偏移(如日志、协议格式)

动态性

偏移量随时间可能变化(夏令时)

偏移量固定不变

示例

Asia/Shanghai  表示上海

+08:00 或 Z

两者的选用原则:

  • 若需表示某个地区的真实时区(如用户所在城市),用ZoneId(自动处理夏令时)。

  • 若只需固定偏移(如网络协议中的时间格式),用ZoneOffset。

 

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号