ZetCode

Java Chronology 接口

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

java.time.chrono.Chronology 接口表示一个用于组织和识别日期的日历系统。它提供了在标准 ISO-8601 日历之外,在不同日历系统中计算日期的规则。

Chronology 由各种日历系统实现,如泰历、回历和日本历。它允许使用非格里高利历的日期。该接口提供了创建日期和查询日历属性的方法。

Chronology 接口概述

Chronology 定义了创建日期对象、确定日历属性以及在日历系统之间转换的方法。它充当 Java 时间 API 中所有日历系统的抽象基类。

public interface Chronology extends Comparable<Chronology> {
    String getId();
    String getCalendarType();
    ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth);
    ChronoLocalDate dateEpochDay(long epochDay);
    ChronoLocalDate dateNow();
    boolean isLeapYear(long prolepticYear);
    int prolepticYear(Era era, int yearOfEra);
    Era eraOf(int eraValue);
    List<Era> eras();
    ValueRange range(ChronoField field);
}

上面的代码展示了 Chronology 接口的关键方法。这些方法允许创建日期、检查闰年和访问日历纪元。每个日历系统都提供了这些方法的自己的实现。

获取可用的 Chronology

Java 提供了几个内置的 Chronology 实现。我们可以使用 getAvailableChronologies 方法列出所有可用的 Chronology。这有助于发现受支持的日历系统。

Main.java
package com.zetcode;

import java.time.chrono.Chronology;
import java.util.Set;

public class Main {

    public static void main(String[] args) {
        
        // Get all available chronologies
        Set<Chronology> chronologies = Chronology.getAvailableChronologies();
        
        System.out.println("Available calendar systems:");
        for (Chronology chrono : chronologies) {
            System.out.println(chrono.getId() + " - " + chrono.getCalendarType());
        }
        
        // Get default ISO chronology
        Chronology iso = Chronology.of("ISO");
        System.out.println("\nDefault chronology: " + iso.getId());
    }
}

此示例列出了 JVM 中所有可用的日历系统。输出通常包括 ISO、泰历、回历和日本历。ISO Chronology 是默认的格里高利历系统。

在不同日历中创建日期

每个 Chronology 都可以创建特定于其日历系统的日期对象。date 方法使用年、月和日的值创建日期。也可以从纪元日创建日期。

Main.java
package com.zetcode;

import java.time.chrono.Chronology;
import java.time.chrono.JapaneseDate;
import java.time.chrono.ThaiBuddhistDate;

public class Main {

    public static void main(String[] args) {
        
        // Create ISO date
        Chronology iso = Chronology.of("ISO");
        var isoDate = iso.date(2025, 4, 15);
        System.out.println("ISO date: " + isoDate);
        
        // Create Japanese date
        Chronology japanese = Chronology.of("Japanese");
        var japaneseDate = japanese.date(2025, 4, 15);
        System.out.println("Japanese date: " + japaneseDate);
        
        // Create Thai Buddhist date
        var thaiDate = ThaiBuddhistDate.now();
        System.out.println("Thai Buddhist date: " + thaiDate);
        
        // Create date from epoch day
        var epochDate = iso.dateEpochDay(10000);
        System.out.println("Date from epoch day: " + epochDate);
    }
}

此示例演示了在不同日历系统中创建日期。请注意,在不同的日历中,相同的年/月/日值如何产生不同的日期。dateEpochDay 方法从自 1970-01-01 以来经过的天数创建日期。

使用日历纪元

许多日历系统使用纪元将时间划分为不同的时期。Chronology 接口提供了使用这些纪元的方法。每个日历都定义了自己的纪元系统。

Main.java
package com.zetcode;

import java.time.chrono.Chronology;
import java.time.chrono.JapaneseDate;
import java.time.chrono.JapaneseEra;
import java.time.chrono.ThaiBuddhistDate;

public class Main {

    public static void main(String[] args) {
        
        // Get eras for Japanese calendar
        Chronology japanese = Chronology.of("Japanese");
        System.out.println("Japanese eras:");
        japanese.eras().forEach(era -> System.out.println(era));
        
        // Create date in specific era
        JapaneseDate jdate = JapaneseDate.of(JapaneseEra.HEISEI, 30, 4, 15);
        System.out.println("\nHeisei era date: " + jdate);
        
        // Convert between era year and proleptic year
        int prolepticYear = japanese.prolepticYear(JapaneseEra.HEISEI, 30);
        System.out.println("Proleptic year: " + prolepticYear);
        
        // Get era of a date
        var thaiDate = ThaiBuddhistDate.now();
        System.out.println("\nThai Buddhist era: " + thaiDate.getEra());
    }
}

此示例展示了如何使用日历纪元。日本历有多个代表天皇统治时期的纪元。prolepticYear 方法在纪元年份和连续年份计数之间进行转换。

检查闰年

不同的日历系统对闰年有不同的规则。isLeapYear 方法根据 Chronology 的规则检查某一年是否为闰年。

Main.java
package com.zetcode;

import java.time.chrono.Chronology;
import java.time.chrono.HijrahChronology;
import java.time.chrono.ThaiBuddhistChronology;

public class Main {

    public static void main(String[] args) {
        
        // Check leap years in different calendars
        Chronology iso = Chronology.of("ISO");
        System.out.println("ISO 2024 is leap: " + iso.isLeapYear(2024));
        
        Chronology thai = ThaiBuddhistChronology.INSTANCE;
        System.out.println("Thai 2567 is leap: " + thai.isLeapYear(2567));
        
        Chronology hijrah = HijrahChronology.INSTANCE;
        System.out.println("Hijrah 1445 is leap: " + hijrah.isLeapYear(1445));
        
        // Range of valid years
        System.out.println("\nISO year range: " + iso.range(ChronoField.YEAR));
    }
}

此示例演示了在不同日历系统中检查闰年。请注意,同一年在一个日历中可能是闰年,而在另一个日历中则不是。range 方法显示了每个日历的有效年份值。

在日历之间转换

日期可以在不同的日历系统之间转换。这对于以多种日历格式显示日期或与旧系统一起使用非常有用。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.JapaneseDate;
import java.time.chrono.ThaiBuddhistDate;

public class Main {

    public static void main(String[] args) {
        
        // Convert ISO to other calendars
        LocalDate isoDate = LocalDate.of(2025, 4, 15);
        System.out.println("ISO date: " + isoDate);
        
        JapaneseDate japaneseDate = JapaneseDate.from(isoDate);
        System.out.println("Japanese date: " + japaneseDate);
        
        ThaiBuddhistDate thaiDate = ThaiBuddhistDate.from(isoDate);
        System.out.println("Thai Buddhist date: " + thaiDate);
        
        // Convert back to ISO
        LocalDate backFromJapanese = LocalDate.from(japaneseDate);
        System.out.println("\nBack to ISO from Japanese: " + backFromJapanese);
        
        // ChronoLocalDate operations
        ChronoLocalDate chronoDate = thaiDate;
        System.out.println("Day of week: " + chronoDate.get(ChronoField.DAY_OF_WEEK));
    }
}

此示例展示了 ISO 和其他日历系统之间的转换。from 方法执行转换,而 ChronoLocalDate 提供了常见的操作。所有转换都保持相同的时间点。

格式化 Chronology 日期

可以使用 DateTimeFormatter 格式化来自不同 Chronology 的日期。格式化程序可以使用 Chronology 特定的模式和区域设置。

Main.java
package com.zetcode;

import java.time.chrono.JapaneseDate;
import java.time.chrono.ThaiBuddhistDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {

    public static void main(String[] args) {
        
        // Format Japanese date
        JapaneseDate jdate = JapaneseDate.now();
        DateTimeFormatter jformatter = DateTimeFormatter
            .ofPattern("GGGG y年 M月 d日")
            .withLocale(Locale.JAPANESE);
        System.out.println("Japanese formatted: " + jformatter.format(jdate));
        
        // Format Thai Buddhist date
        ThaiBuddhistDate tdate = ThaiBuddhistDate.now();
        DateTimeFormatter tformatter = DateTimeFormatter
            .ofPattern("G y年 M月 d日")
            .withLocale(new Locale("th", "TH"));
        System.out.println("Thai formatted: " + tformatter.format(tdate));
        
        // Parse date in different chronology
        String text = "令和 7年 4月 15日";
        JapaneseDate parsed = JapaneseDate.parse(text, jformatter);
        System.out.println("\nParsed Japanese date: " + parsed);
    }
}

此示例演示了在不同日历系统中格式化和解析日期。格式化程序使用特定于区域设置的模式和纪元名称。请注意,对于日本日期,使用 GGGG 表示完整的纪元名称。

来源

Java Chronology 接口文档

在本文中,我们介绍了 Java Chronology 接口的基本方法和功能。理解这些概念对于在 Java 应用程序中使用多个日历系统至关重要。

作者

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

列出所有Java教程