ZetCode

Java ZoneId 类

最后修改时间:2025 年 4 月 16 日

java.time.ZoneId 类表示时区标识符。 它用于识别在 Instant 和 LocalDateTime 之间进行转换的规则。 ZoneId 取代了旧的 TimeZone 类。

ZoneId 是不可变的且线程安全的。 它支持固定偏移量和地理区域。 该类提供对时区转换规则的访问。 所有时区规则均由 IANA 时区数据库定义。

ZoneId 类概述

ZoneId 提供了获取系统默认时区、从 ID 创建时区以及列出可用时区的方法。 主要操作包括在时间类型之间进行转换以及检查夏令时规则。 该类处理时区 ID 和固定偏移量。

public abstract class ZoneId implements Serializable {
    public static ZoneId systemDefault();
    public static ZoneId of(String zoneId);
    public static Set<String> getAvailableZoneIds();
    public abstract String getId();
    public abstract ZoneRules getRules();
    public boolean equals(Object obj);
    public static ZoneId from(TemporalAccessor temporal);
}

上面的代码显示了 ZoneId 提供的关键方法。 这些方法允许创建、比较和检查时区。 该类通过 ZoneRules 类提供对详细时区规则的访问。

创建 ZoneId 对象

可以通过多种方式创建 ZoneId 对象。 最常用的方法是使用 of 获取特定时区,以及使用 systemDefault 获取 JVM 的当前时区。 该类还支持从字符串解析。

Main.java
package com.zetcode; 

import java.time.ZoneId;

public class Main {

    public static void main(String[] args) {
        
        // System default time zone
        ZoneId systemZone = ZoneId.systemDefault();
        System.out.println("System default: " + systemZone);
        
        // Create from zone ID
        ZoneId parisZone = ZoneId.of("Europe/Paris");
        System.out.println("Paris zone: " + parisZone);
        
        // Create from offset
        ZoneId offsetZone = ZoneId.of("+02:00");
        System.out.println("Fixed offset: " + offsetZone);
        
        // Using ZoneId.SHORT_IDS
        ZoneId pstZone = ZoneId.of("PST", ZoneId.SHORT_IDS);
        System.out.println("PST zone: " + pstZone);
    }
}

此示例演示了创建 ZoneId 对象的不同方法。 输出显示了各种时区表示形式。 请注意,像 "PST" 这样的短 ID 已弃用,应在新代码中避免使用。

列出可用时区

ZoneId 类提供对所有可用时区 ID 的访问。 这对于向用户显示时区选项或验证时区字符串非常有用。 这些 ID 遵循 IANA 时区数据库格式。

Main.java
package com.zetcode; 

import java.time.ZoneId;
import java.util.Set;

public class Main {

    public static void main(String[] args) {

        // Get all available zone IDs
        Set<String> zoneIds = ZoneId.getAvailableZoneIds();
        
        // Print first 10 zones
        zoneIds.stream()
               .sorted()
               .limit(10)
               .forEach(System.out::println);
               
        // Count total zones
        System.out.println("Total available zones: " + zoneIds.size());
        
        // Check if a zone exists
        String zoneToCheck = "America/New_York";
        System.out.println(zoneToCheck + " exists: " + 
            zoneIds.contains(zoneToCheck));
    }
}

此示例显示了如何访问所有可用时区 ID。 该集合包含 600 多个条目。 这些 ID 按地区和城市排序,使其适合用户选择界面。

使用区域规则

每个 ZoneId 都提供对其 ZoneRules 的访问,其中包含有关时区行为的详细信息。 这包括偏移转换、夏令时规则和历史更改。

Main.java
package com.zetcode; 

import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.zone.ZoneRules;

public class Main {

    public static void main(String[] args) {

        ZoneId zone = ZoneId.of("America/New_York");
        ZoneRules rules = zone.getRules();
        
        // Current standard offset
        ZoneOffset currentOffset = rules.getOffset(java.time.Instant.now());
        System.out.println("Current offset: " + currentOffset);
        
        // Is daylight saving in effect?
        System.out.println("Is DST: " + rules.isDaylightSavings(
            java.time.Instant.now()));
            
        // Next transition
        System.out.println("Next transition: " + 
            rules.nextTransition(java.time.Instant.now()));
            
        // Standard offset
        System.out.println("Standard offset: " + rules.getStandardOffset(
            java.time.Instant.now()));
    }
}

此示例演示了如何访问详细的时区规则。 ZoneRules 对象提供有关特定时刻时区行为的信息。 这对于处理夏令时转换特别有用。

在时间类型之间转换

ZoneId 通常用于在 Instant 和 LocalDateTime 之间进行转换。 当处理机器和人类时间表示时,这些转换至关重要。

Main.java
package com.zetcode; 

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Main {

    public static void main(String[] args) {

        ZoneId zone = ZoneId.of("Europe/Berlin");
        Instant now = Instant.now();
        
        // Convert Instant to ZonedDateTime
        ZonedDateTime zoned = now.atZone(zone);
        System.out.println("In Berlin: " + zoned);
        
        // Convert LocalDateTime to ZonedDateTime
        LocalDateTime local = LocalDateTime.now();
        ZonedDateTime zonedLocal = local.atZone(zone);
        System.out.println("Local in Berlin: " + zonedLocal);
        
        // Convert ZonedDateTime to Instant
        Instant back = zoned.toInstant();
        System.out.println("Back to instant: " + back);
        
        // Convert between zones
        ZonedDateTime nyTime = zoned.withZoneSameInstant(ZoneId.of("America/New_York"));
        System.out.println("In New York: " + nyTime);
    }
}

此示例显示了使用 ZoneId 在不同时间类型之间进行的转换。 atZone 方法将时区信息附加到 Instant 或 LocalDateTime。 区域之间的转换保留了同一时刻的时间。

处理夏令时

ZoneId 自动处理夏令时转换。 该类提供了检查 DST 是否生效以及计算适当偏移量的方法。 这确保了全年正确的计时计算。

Main.java
package com.zetcode; 

import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Main {

    public static void main(String[] args) {

        ZoneId zone = ZoneId.of("America/New_York");
        
        // Before DST transition (March 12, 2023 1:59 AM)
        LocalDateTime before = LocalDateTime.of(2023, Month.MARCH, 12, 1, 59);
        ZonedDateTime beforeZoned = before.atZone(zone);
        System.out.println("Before transition: " + beforeZoned);
        
        // After DST transition (March 12, 2023 3:00 AM)
        LocalDateTime after = LocalDateTime.of(2023, Month.MARCH, 12, 3, 0);
        ZonedDateTime afterZoned = after.atZone(zone);
        System.out.println("After transition: " + afterZoned);
        
        // Check DST in effect
        System.out.println("Is DST in July: " + 
            zone.getRules().isDaylightSavings(
                LocalDateTime.of(2023, Month.JULY, 1, 0, 0).atZone(zone).toInstant()));
    }
}

此示例演示了夏令时处理。 America/New_York 时区于 2023 年 3 月 12 日转换为 DST。 请注意时钟如何从凌晨 1:59 直接跳到凌晨 3:00,跳过了无效的小时。

使用固定偏移量

ZoneId 支持固定偏移量时区,这些时区不遵守夏令时。 当处理需要简单的基于偏移量的时区而无需区域规则的系统时,这些非常有用。

Main.java
package com.zetcode; 

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class Main {

    public static void main(String[] args) {

        // Create fixed offset zone
        ZoneId fixedZone = ZoneId.of("+05:30");
        System.out.println("Fixed zone: " + fixedZone);
        
        // Using ZoneOffset
        ZoneOffset offset = ZoneOffset.ofHoursMinutes(5, 30);
        ZoneId offsetZone = ZoneId.ofOffset("UTC", offset);
        System.out.println("Offset zone: " + offsetZone);
        
        // Convert with fixed offset
        LocalDateTime local = LocalDateTime.now();
        ZonedDateTime zoned = local.atZone(offsetZone);
        System.out.println("With offset: " + zoned);
        
        // Check if fixed
        System.out.println("Is fixed offset: " + 
            offsetZone.getRules().isFixedOffset());
    }
}

此示例显示了如何使用固定偏移量时区。 固定偏移量全年不变,使其比区域时区更简单但灵活性更低。 ZoneOffset 类提供其他特定于偏移量的功能。

来源

Java ZoneId 类文档

在本文中,我们介绍了 Java ZoneId 类的基本方法和功能。 了解这些概念对于在现代 Java 应用程序中进行准确的时区处理至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的专注程序员。 我于 2007 年开始撰写编程文章,至今已撰写了超过 1,400 篇文章和八本电子书。 凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程