ZetCode

Java ChronoField 枚举

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

java.time.temporal.ChronoField 枚举实现了 TemporalField 接口,代表日期和时间的标准字段。它提供了诸如年、月、日、小时、分钟和秒之类的单位。每个字段都有一个有效值的范围。

ChronoField 用于像 LocalDateLocalTimeZonedDateTime 这样的时间对象。它允许访问日期时间对象的特定组件。枚举包含与日期和时间相关的字段。

ChronoField 枚举概述

ChronoField 提供了所有标准日期时间字段的常量。每个字段都有获取其范围和基本单位的方法。该枚举实现了 TemporalField 接口,用于时间访问和调整。

public enum ChronoField implements TemporalField {
    NANO_OF_SECOND, NANO_OF_DAY,
    MICRO_OF_SECOND, MICRO_OF_DAY,
    MILLI_OF_SECOND, MILLI_OF_DAY,
    SECOND_OF_MINUTE, SECOND_OF_DAY,
    MINUTE_OF_HOUR, MINUTE_OF_DAY,
    HOUR_OF_AMPM, HOUR_OF_DAY,
    AMPM_OF_DAY,
    DAY_OF_WEEK, DAY_OF_MONTH, DAY_OF_YEAR,
    EPOCH_DAY,
    ALIGNED_WEEK_OF_MONTH, ALIGNED_WEEK_OF_YEAR,
    ALIGNED_DAY_OF_WEEK_IN_MONTH, ALIGNED_DAY_OF_WEEK_IN_YEAR,
    MONTH_OF_YEAR, PROLEPTIC_MONTH,
    YEAR_OF_ERA, YEAR,
    ERA,
    INSTANT_SECONDS, OFFSET_SECONDS;
    
    // Methods
    public ValueRange range();
    public boolean isDateBased();
    public boolean isTimeBased();
    public TemporalUnit getBaseUnit();
    public TemporalUnit getRangeUnit();
}

以上代码显示了枚举常量和关键方法。字段分为基于日期或基于时间。每个字段都有一个定义的有效值范围,可通过 range() 方法访问。

访问日期组件

ChronoField 可以提取日期组件,如年、月和日。基于日期的字段与包含日期信息的时间对象一起使用。该示例显示了常见的日期字段操作。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.temporal.ChronoField;

public class Main {

    public static void main(String[] args) {
        
        LocalDate date = LocalDate.of(2025, 4, 15);
        
        // Get year
        int year = date.get(ChronoField.YEAR);
        System.out.println("Year: " + year);
        
        // Get month
        int month = date.get(ChronoField.MONTH_OF_YEAR);
        System.out.println("Month: " + month);
        
        // Get day of month
        int day = date.get(ChronoField.DAY_OF_MONTH);
        System.out.println("Day: " + day);
        
        // Get day of year
        int dayOfYear = date.get(ChronoField.DAY_OF_YEAR);
        System.out.println("Day of year: " + dayOfYear);
        
        // Check if field is supported
        boolean supported = date.isSupported(ChronoField.ERA);
        System.out.println("ERA supported: " + supported);
    }
}

此示例演示了如何使用 ChronoField 访问日期组件。get() 方法从时间对象中检索字段值。isSupported() 检查某个字段是否适用于时间类型。

访问时间组件

基于时间的字段提供对小时、分钟、秒和纳秒值的访问。这些字段与包含时间信息的时间对象一起使用。该示例显示了常见的时间字段操作。

Main.java
package com.zetcode;

import java.time.LocalTime;
import java.time.temporal.ChronoField;

public class Main {

    public static void main(String[] args) {
        
        LocalTime time = LocalTime.of(14, 30, 45, 500_000);
        
        // Get hour
        int hour = time.get(ChronoField.HOUR_OF_DAY);
        System.out.println("Hour: " + hour);
        
        // Get minute
        int minute = time.get(ChronoField.MINUTE_OF_HOUR);
        System.out.println("Minute: " + minute);
        
        // Get second
        int second = time.get(ChronoField.SECOND_OF_MINUTE);
        System.out.println("Second: " + second);
        
        // Get nano
        int nano = time.get(ChronoField.NANO_OF_SECOND);
        System.out.println("Nanosecond: " + nano);
        
        // Check AM/PM
        int ampm = time.get(ChronoField.AMPM_OF_DAY);
        System.out.println("AMPM: " + (ampm == 0 ? "AM" : "PM"));
    }
}

此示例展示了如何使用 ChronoField 访问时间组件。HOUR_OF_DAY 提供 24 小时制,而 AMPM_OF_DAY 区分上午和下午。所有时间字段都有定义的范围。

使用日期时间对象

ChronoField 与完整的日期时间对象(如 LocalDateTimeZonedDateTime)一起使用。可以从这些对象访问日期和时间字段。

Main.java
package com.zetcode;

import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;

public class Main {

    public static void main(String[] args) {
        
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println("Current date-time: " + ldt);
        
        // Get combined fields
        int year = ldt.get(ChronoField.YEAR);
        int hour = ldt.get(ChronoField.HOUR_OF_DAY);
        System.out.printf("Year: %d, Hour: %d%n", year, hour);
        
        ZonedDateTime zdt = ZonedDateTime.now();
        System.out.println("Zoned date-time: " + zdt);
        
        // Get day of week (1-7)
        int dow = zdt.get(ChronoField.DAY_OF_WEEK);
        System.out.println("Day of week: " + dow);
        
        // Get epoch day
        long epochDay = zdt.getLong(ChronoField.EPOCH_DAY);
        System.out.println("Epoch day: " + epochDay);
    }
}

此示例演示了如何将 ChronoField 与日期时间对象一起使用。可以从同一对象访问日期和时间字段。某些字段(如 EPOCH_DAY)返回 long 值而不是整数。

字段验证和范围

每个 ChronoField 都有定义的有效值范围。可以在访问字段之前检查这些范围。range() 方法提供最小值和最大值。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.temporal.ChronoField;
import java.time.temporal.ValueRange;

public class Main {

    public static void main(String[] args) {
        
        // Get range for day of month
        ValueRange dayRange = ChronoField.DAY_OF_MONTH.range();
        System.out.println("Day of month range: " + dayRange);
        
        // Get range for month
        ValueRange monthRange = ChronoField.MONTH_OF_YEAR.range();
        System.out.println("Month range: " + monthRange);
        
        // Check if value is valid
        LocalDate date = LocalDate.of(2025, 2, 1);
        boolean valid = date.isSupported(ChronoField.DAY_OF_MONTH) && 
                      date.range(ChronoField.DAY_OF_MONTH).isValidValue(30);
        System.out.println("Is 30 valid for February: " + valid);
        
        // Check hour range
        ValueRange hourRange = ChronoField.HOUR_OF_DAY.range();
        System.out.println("Hour range: " + hourRange);
    }
}

此示例展示了如何使用字段范围和验证。range() 方法返回最小和最大的有效值。isValidValue() 检查特定值对于该字段是否有效。

调整时间对象

ChronoField 可用于调整时间对象。with() 方法创建一个带有修改字段的新对象。这对于日期时间操作很有用。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoField;

public class Main {

    public static void main(String[] args) {
        
        LocalDate date = LocalDate.of(2025, 4, 15);
        System.out.println("Original date: " + date);
        
        // Change year
        LocalDate newYear = date.with(ChronoField.YEAR, 2026);
        System.out.println("New year: " + newYear);
        
        // Change month
        LocalDate newMonth = date.with(ChronoField.MONTH_OF_YEAR, 12);
        System.out.println("New month: " + newMonth);
        
        LocalDateTime dateTime = LocalDateTime.now();
        System.out.println("Original date-time: " + dateTime);
        
        // Change hour
        LocalDateTime newHour = dateTime.with(ChronoField.HOUR_OF_DAY, 23);
        System.out.println("New hour: " + newHour);
        
        // Change minute
        LocalDateTime newMinute = dateTime.with(ChronoField.MINUTE_OF_HOUR, 0);
        System.out.println("New minute: " + newMinute);
    }
}

此示例演示了如何使用 ChronoField 调整时间对象。with() 方法返回一个新对象,其中指定的字段已更改。原始对象保持不可变,这符合 Java Time API 的设计。

特殊字段和转换

ChronoField 包括用于转换的特殊字段,如 EPOCH_DAYINSTANT_SECONDS。这些字段允许使用不同的时间表示方式。

Main.java
package com.zetcode;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;

public class Main {

    public static void main(String[] args) {
        
        // EPOCH_DAY example
        LocalDate date = LocalDate.of(2025, 1, 1);
        long epochDay = date.getLong(ChronoField.EPOCH_DAY);
        System.out.println("Epoch day: " + epochDay);
        
        // Convert back from epoch day
        LocalDate fromEpoch = LocalDate.ofEpochDay(epochDay);
        System.out.println("From epoch day: " + fromEpoch);
        
        // INSTANT_SECONDS example
        ZonedDateTime zdt = ZonedDateTime.now();
        long instantSeconds = zdt.getLong(ChronoField.INSTANT_SECONDS);
        System.out.println("Instant seconds: " + instantSeconds);
        
        // Convert back from instant seconds
        Instant instant = Instant.ofEpochSecond(instantSeconds);
        System.out.println("From instant seconds: " + instant);
    }
}

此示例显示了用于时间转换的特殊字段。EPOCH_DAY 表示自 1970-01-01 以来的天数,而 INSTANT_SECONDS 表示自同一纪元以来的秒数。这些字段允许在不同的时间表示之间进行互操作。

来源

Java ChronoField 枚举文档

在本文中,我们介绍了 Java ChronoField 枚举的基本字段和特性。理解这些概念对于在 Java 应用程序中使用日期和时间组件至关重要。

作者

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

列出所有Java教程