ZetCode

Java ZonedDateTime 类

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

java.time.ZonedDateTime 类表示带时区的日期时间。它结合了 LocalDateTime 和 ZoneId 来处理时区规则。这个类是不可变的且线程安全的。

当时区上下文很重要时,使用 ZonedDateTime。它会自动处理夏令时。该类提供高达纳秒的精度,并遵循 ISO-8601 日历系统。

ZonedDateTime 类概述

ZonedDateTime 提供了创建、操作和格式化日期时间值的方法。它可以在时区之间转换并处理夏令时。该类是 Java 8 中引入的现代日期时间 API 的一部分。

public final class ZonedDateTime implements Temporal, ChronoZonedDateTime<LocalDate>, 
    Serializable {
    public static ZonedDateTime now();
    public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone);
    public static ZonedDateTime parse(CharSequence text);
    public ZoneId getZone();
    public ZonedDateTime withZoneSameInstant(ZoneId zone);
    public LocalDateTime toLocalDateTime();
    public Instant toInstant();
    public boolean isBefore(ChronoZonedDateTime<?> other);
    public boolean isAfter(ChronoZonedDateTime<?> other);
}

上面的代码展示了 ZonedDateTime 的关键方法。这些方法允许进行时区感知的日期时间操作。该类会自动处理所有时区转换和夏令时调整。

创建 ZonedDateTime 对象

可以以多种方式创建 ZonedDateTime 对象。最常用的方法是使用 now 获取当前时间,以及使用工厂方法创建特定值。也支持从字符串解析。

Main.java
package com.zetcode; 

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

public class Main {

    public static void main(String[] args) {
        
        // Current date-time with timezone
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println("Current ZonedDateTime: " + now);
        
        // Specific timezone
        ZonedDateTime parisTime = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
        System.out.println("Paris time: " + parisTime);
        
        // From LocalDateTime
        LocalDateTime ldt = LocalDateTime.of(2025, 6, 15, 10, 30);
        ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.of("America/New_York"));
        System.out.println("From LocalDateTime: " + zdt);
        
        // From string
        ZonedDateTime parsed = ZonedDateTime.parse("2025-01-01T12:00:00+01:00[Europe/Berlin]");
        System.out.println("Parsed from string: " + parsed);
    }
}

此示例展示了创建 ZonedDateTime 对象的不同方法。输出包括日期时间信息和时区信息。请注意时区如何影响显示的日期时间值。

获取 ZonedDateTime 组件

ZonedDateTime 可以分解成它的组成部分,例如年、月和时区。这些值对于显示或进一步计算很有用。该类提供了所有组件的 getter 方法。

Main.java
package com.zetcode; 

import java.time.ZonedDateTime;
import java.time.ZoneId;

public class Main {

    public static void main(String[] args) {

        ZonedDateTime zdt = ZonedDateTime.now();
        
        // Get date and time components
        System.out.println("Year: " + zdt.getYear());
        System.out.println("Month: " + zdt.getMonth());
        System.out.println("Day: " + zdt.getDayOfMonth());
        System.out.println("Hour: " + zdt.getHour());
        System.out.println("Minute: " + zdt.getMinute());
        
        // Get timezone information
        ZoneId zone = zdt.getZone();
        System.out.println("Timezone: " + zone.getId());
        
        // Get offset from UTC
        System.out.println("Offset: " + zdt.getOffset());
    }
}

此示例演示了如何从 ZonedDateTime 提取组件。时区信息包括区域 ID 和 UTC 偏移量。所有组件都反映了指定时区中的值。

转换时区

ZonedDateTime 可以在不同的时区之间转换,同时保留时间点。这对于在不同位置显示同一时刻很有用。转换会自动处理夏令时。

Main.java
package com.zetcode; 

import java.time.ZonedDateTime;
import java.time.ZoneId;

public class Main {

    public static void main(String[] args) {

        ZonedDateTime nyTime = ZonedDateTime.now(ZoneId.of("America/New_York"));
        System.out.println("New York time: " + nyTime);
        
        // Convert to London time
        ZonedDateTime londonTime = nyTime.withZoneSameInstant(ZoneId.of("Europe/London"));
        System.out.println("London time: " + londonTime);
        
        // Convert to Tokyo time
        ZonedDateTime tokyoTime = nyTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
        System.out.println("Tokyo time: " + tokyoTime);
        
        // Keep local time, change only timezone
        ZonedDateTime sameLocal = nyTime.withZoneSameLocal(ZoneId.of("Europe/Paris"));
        System.out.println("Same local time in Paris: " + sameLocal);
    }
}

此示例显示了使用 ZonedDateTime 进行时区转换。withZoneSameInstant 方法更改时区,同时保持相同的时刻。withZoneSameLocal 保留本地时间值。

比较 ZonedDateTime

ZonedDateTime 对象可以按时间顺序进行比较。比较考虑了时间点和时区规则。这确保了跨时区的事件的准确排序。

Main.java
package com.zetcode; 

import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.Duration;

public class Main {

    public static void main(String[] args) {

        ZonedDateTime nyTime = ZonedDateTime.now(ZoneId.of("America/New_York"));
        ZonedDateTime londonTime = nyTime.withZoneSameInstant(ZoneId.of("Europe/London"));
        ZonedDateTime futureTime = nyTime.plusHours(2);
        
        System.out.println("NY before London: " + nyTime.isBefore(londonTime));
        System.out.println("NY after future: " + nyTime.isAfter(futureTime));
        System.out.println("Compare NY and London: " + nyTime.compareTo(londonTime));
        
        // Time difference between zones
        Duration offsetDiff = Duration.between(nyTime.toLocalTime(), londonTime.toLocalTime());
        System.out.println("Time difference: " + offsetDiff.toHours() + " hours");
    }
}

此示例演示了比较 ZonedDateTime 对象。比较方法考虑了实际的时间点,而不仅仅是本地时间值。时间差计算显示了时区之间的当前偏移量。

使用夏令时

ZonedDateTime 自动处理夏令时转换。它根据时区规则调整时间值。这确保了全年正确的时间表示。

Main.java
package com.zetcode; 

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

public class Main {

    public static void main(String[] args) {

        ZoneId nyZone = ZoneId.of("America/New_York");
        
        // Before DST transition (March 10, 2025 1:59 AM)
        ZonedDateTime beforeDST = ZonedDateTime.of(2025, 3, 10, 1, 59, 0, 0, nyZone);
        System.out.println("Before DST: " + beforeDST);
        
        // After DST transition (1 hour later)
        ZonedDateTime afterDST = beforeDST.plusHours(1);
        System.out.println("After DST: " + afterDST);
        
        // Check if DST is in effect
        System.out.println("Is DST: " + afterDST.getZone().getRules().isDaylightSavings(afterDST.toInstant()));
        
        // November DST end
        ZonedDateTime endDST = ZonedDateTime.of(2025, 11, 2, 1, 59, 0, 0, nyZone);
        System.out.println("Before DST end: " + endDST);
        System.out.println("After DST end: " + endDST.plusHours(1));
    }
}

此示例显示了 ZonedDateTime 处理夏令时转换。自动处理了春季和秋季的时间调整。可以检查任何特定时刻的 DST 状态。

转换为其他类型

ZonedDateTime 可以转换为其他日期时间类型,例如 LocalDateTime 或 Instant。当不再需要时区信息或使用旧版 API 时,这些转换很有用。

Main.java
package com.zetcode; 

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

public class Main {

    public static void main(String[] args) {

        ZonedDateTime zdt = ZonedDateTime.now();
        
        // Convert to LocalDateTime (loses timezone)
        LocalDateTime ldt = zdt.toLocalDateTime();
        System.out.println("LocalDateTime: " + ldt);
        
        // Convert to Instant (UTC)
        Instant instant = zdt.toInstant();
        System.out.println("Instant: " + instant);
        
        // Convert to OffsetDateTime (keeps offset but not zone ID)
        OffsetDateTime odt = zdt.toOffsetDateTime();
        System.out.println("OffsetDateTime: " + odt);
        
        // Convert back to ZonedDateTime
        ZonedDateTime back = instant.atZone(zdt.getZone());
        System.out.println("Back to ZonedDateTime: " + back);
    }
}

此示例演示了 ZonedDateTime 和其他日期时间类型之间的转换。每次转换都有不同的目的,具体取决于是否需要时区、偏移量或 UTC 时间。可以重建原始的 ZonedDateTime。

来源

Java ZonedDateTime 类文档

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

作者

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

列出所有Java教程