ZetCode

Java ZoneRules 类

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

java.time.zone.ZoneRules 类表示时区的一组规则。它定义了特定区域的 UTC 偏移量随时间的变化。ZoneRules 处理夏令时转换和历史变动。

ZoneRules 是不可变的且线程安全的。它通常从 ZoneId 获取,并提供有关时区行为的详细信息。该类包含特定时区的所有转换规则。

ZoneRules 类概述

ZoneRules 提供了查询偏移量变化、转换和夏令时信息的方法。关键操作包括检查固定偏移量、获取当前规则以及检查历史转换。

public final class ZoneRules implements Serializable {
    public boolean isFixedOffset();
    public ZoneOffset getOffset(Instant instant);
    public ZoneOffset getOffset(LocalDateTime localDateTime);
    public List<ZoneOffsetTransition> getTransitions();
    public List<ZoneOffsetTransitionRule> getTransitionRules();
    public boolean isDaylightSavings(Instant instant);
    public Duration getDaylightSavings(Instant instant);
    public boolean isValidOffset(LocalDateTime localDateTime, ZoneOffset offset);
}

以上代码显示了 ZoneRules 提供的关键方法。这些方法允许检查特定时刻的时区行为。该类处理固定偏移量时区和具有夏令时的时区。

获取 ZoneRules

ZoneRules 对象通常通过 ZoneId 实例获取。系统时区数据库提供标准时区的规则。您也可以根据需要创建自定义规则。

Main.java
package com.zetcode; 

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

public class Main {

    public static void main(String[] args) {
        
        // Get rules for system default timezone
        ZoneRules defaultRules = ZoneId.systemDefault().getRules();
        System.out.println("System default rules: " + defaultRules);
        
        // Get rules for specific timezone
        ZoneRules parisRules = ZoneId.of("Europe/Paris").getRules();
        System.out.println("Paris rules: " + parisRules);
        
        // Check if fixed offset
        System.out.println("Is fixed offset: " + parisRules.isFixedOffset());
        
        // Get rules for UTC
        ZoneRules utcRules = ZoneId.of("UTC").getRules();
        System.out.println("UTC rules: " + utcRules);
        System.out.println("UTC fixed offset: " + utcRules.isFixedOffset());
    }
}

此示例演示了如何为不同的时区获取 ZoneRules。输出显示 UTC 具有固定偏移量规则,而巴黎具有夏令时转换。系统默认规则取决于 JVM 的环境。

获取 Instant 的偏移量

ZoneRules 可以确定特定时刻的 UTC 偏移量。这对于在本地时间和 UTC 之间进行转换至关重要。该方法考虑了所有历史转换。

Main.java
package com.zetcode; 

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

public class Main {

    public static void main(String[] args) {
        
        ZoneRules nyRules = ZoneId.of("America/New_York").getRules();
        
        // Current offset
        Instant now = Instant.now();
        System.out.println("Current NY offset: " + nyRules.getOffset(now));
        
        // Winter time
        Instant winter = Instant.parse("2025-01-15T12:00:00Z");
        System.out.println("Winter NY offset: " + nyRules.getOffset(winter));
        
        // Summer time
        Instant summer = Instant.parse("2025-06-15T12:00:00Z");
        System.out.println("Summer NY offset: " + nyRules.getOffset(summer));
        
        // Historical change (before 2007 rules)
        Instant oldDate = Instant.parse("2000-06-15T12:00:00Z");
        System.out.println("2000 summer offset: " + nyRules.getOffset(oldDate));
    }
}

此示例显示了如何获取纽约不同时刻的 UTC 偏移量。输出演示了夏令时变化和历史规则差异。该方法自动处理所有转换。

检查夏令时

ZoneRules 提供了方法来检查特定时刻是否生效夏令时。它还可以返回夏令时调整量。这些方法对于时区感知计算很有用。

Main.java
package com.zetcode; 

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

public class Main {

    public static void main(String[] args) {
        
        ZoneRules londonRules = ZoneId.of("Europe/London").getRules();
        
        Instant winter = Instant.parse("2025-01-15T12:00:00Z");
        Instant summer = Instant.parse("2025-06-15T12:00:00Z");
        
        System.out.println("Winter DST: " + londonRules.isDaylightSavings(winter));
        System.out.println("Summer DST: " + londonRules.isDaylightSavings(summer));
        
        System.out.println("Winter DST amount: " + londonRules.getDaylightSavings(winter));
        System.out.println("Summer DST amount: " + londonRules.getDaylightSavings(summer));
        
        // Transition moment
        Instant transition = Instant.parse("2025-03-30T01:00:00Z");
        System.out.println("Transition moment DST: " + 
            londonRules.isDaylightSavings(transition));
    }
}

此示例检查伦敦在不同时刻的夏令时状态。getDaylightSavings 方法返回 DST 调整的持续时间。请注意,转换时刻的处理取决于确切的规则。

检查转换

ZoneRules 提供了访问时区所有历史和未来转换规则的权限。这些转换代表了 UTC 偏移量变化的时刻,通常用于夏令时。

Main.java
package com.zetcode; 

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

public class Main {

    public static void main(String[] args) {
        
        ZoneRules tokyoRules = ZoneId.of("Asia/Tokyo").getRules();
        
        // Tokyo has no DST, so transitions list is empty
        System.out.println("Tokyo transitions: " + tokyoRules.getTransitions().size());
        
        ZoneRules chicagoRules = ZoneId.of("America/Chicago").getRules();
        
        // Get all defined transitions
        System.out.println("\nChicago transitions:");
        for (ZoneOffsetTransition trans : chicagoRules.getTransitions()) {
            System.out.println(trans);
        }
        
        // Get transition rules (recurring patterns)
        System.out.println("\nChicago transition rules:");
        chicagoRules.getTransitionRules().forEach(System.out::println);
    }
}

此示例检查东京(无 DST)和芝加哥(有 DST)的转换。getTransitions 方法返回历史变化,而 getTransitionRules 提供重复模式。东京未显示任何转换,因为它不遵守 DST。

验证本地日期时间偏移量

ZoneRules 可以验证特定的本地日期时间组合和偏移量对于该时区是否有效。这对于在 DST 转换期间检查不明确或无效的时间很有用。

Main.java
package com.zetcode; 

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

public class Main {

    public static void main(String[] args) {
        
        ZoneRules nyRules = ZoneId.of("America/New_York").getRules();
        
        // Normal time
        LocalDateTime normalTime = LocalDateTime.of(2025, 1, 15, 12, 0);
        System.out.println("Normal time valid: " + 
            nyRules.isValidOffset(normalTime, ZoneOffset.ofHours(-5)));
        
        // DST transition forward (2 AM becomes 3 AM)
        LocalDateTime springForward = LocalDateTime.of(2025, 3, 9, 2, 30);
        System.out.println("Spring forward valid: " + 
            nyRules.isValidOffset(springForward, ZoneOffset.ofHours(-5)));
        System.out.println("Spring forward valid DST: " + 
            nyRules.isValidOffset(springForward, ZoneOffset.ofHours(-4)));
            
        // DST transition backward (ambiguous time)
        LocalDateTime fallBack = LocalDateTime.of(2025, 11, 2, 1, 30);
        System.out.println("Fall back valid standard: " + 
            nyRules.isValidOffset(fallBack, ZoneOffset.ofHours(-5)));
        System.out.println("Fall back valid DST: " + 
            nyRules.isValidOffset(fallBack, ZoneOffset.ofHours(-4)));
    }
}

此示例验证正常时间和 DST 转换期间的偏移量组合。春季前移转换会创建一个无效时间(凌晨 2:30 不存在)。秋季后退转换会产生歧义(凌晨 1:30 出现两次)。

使用固定偏移量时区

某些时区具有永不改变的固定偏移量。ZoneRules 为这些情况提供了特殊处理,其行为比具有转换的时区更简单。

Main.java
package com.zetcode; 

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

public class Main {

    public static void main(String[] args) {
        
        // Fixed offset zone
        ZoneOffset fixedOffset = ZoneOffset.ofHours(3);
        ZoneRules fixedRules = fixedOffset.getRules();
        
        System.out.println("Is fixed offset: " + fixedRules.isFixedOffset());
        
        // Offset is always the same
        Instant now = Instant.now();
        System.out.println("Current offset: " + fixedRules.getOffset(now));
        
        Instant future = now.plusSeconds(3600 * 24 * 365 * 10); // 10 years later
        System.out.println("Future offset: " + fixedRules.getOffset(future));
        
        // No transitions
        System.out.println("Transitions: " + fixedRules.getTransitions().size());
        System.out.println("Transition rules: " + fixedRules.getTransitionRules().size());
        
        // Always no DST
        System.out.println("DST active: " + fixedRules.isDaylightSavings(now));
    }
}

此示例演示了固定偏移量时区的行为。无论查询的时刻如何,偏移量永远不会改变。对于固定偏移量时区,没有转换,夏令时也永远不会生效。

来源

Java ZoneRules 类文档

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

作者

我叫 Jan Bodnar,是一位经验丰富的程序员,在该领域拥有多年的经验。我从 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和 8 本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程