ZetCode

Java Period 类

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

java.time.Period 类表示基于日期的时长,以年、月和日为单位。它模拟了以日历字段表示的时间量或时长。 Period 用于修改或计算日期之间的差异。

Period 是不可变的且线程安全的。它通常用于基于日期的计算,例如向日期添加月份或查找年龄。该类自动处理夏令时和其他日历不规则性。

Period 类概述

Period 提供了创建 Period、解析字符串和执行计算的方法。关键操作包括添加到日期、比较 Period 和提取组件。该类分别处理年、月和日。

public final class Period implements ChronoPeriod, Serializable {
    public static Period of(int years, int months, int days);
    public static Period ofYears(int years);
    public static Period ofMonths(int months);
    public static Period ofDays(int days);
    public static Period between(LocalDate start, LocalDate end);
    public static Period parse(CharSequence text);
    public int getYears();
    public int getMonths();
    public int getDays();
    public boolean isZero();
    public boolean isNegative();
    public Period plus(Period amountToAdd);
    public Period minus(Period amountToSubtract);
    public Period normalized();
}

上面的代码显示了 Period 提供的关键方法。这些方法允许创建、比较和操作 Period。该类处理基于日期的计算,同时考虑了不同的月份长度和闰年。

创建 Period 对象

Period 对象可以通过几种方式创建。最常见的方法是用于特定持续时间的工厂方法和从字符串解析。 between 方法计算日期之间的 Period。

Main.java
package com.zetcode; 

import java.time.Period;
import java.time.LocalDate;

public class Main {

    public static void main(String[] args) {
        
        // Using factory methods
        Period oneYear = Period.ofYears(1);
        System.out.println("One year: " + oneYear);
        
        Period twoMonths = Period.ofMonths(2);
        System.out.println("Two months: " + twoMonths);
        
        Period threeDays = Period.ofDays(3);
        System.out.println("Three days: " + threeDays);
        
        // Combined period
        Period complex = Period.of(1, 2, 3);
        System.out.println("1 year, 2 months, 3 days: " + complex);
        
        // From dates
        LocalDate start = LocalDate.of(2025, 1, 1);
        LocalDate end = LocalDate.of(2026, 3, 15);
        Period between = Period.between(start, end);
        System.out.println("Between dates: " + between);
        
        // From string
        Period parsed = Period.parse("P1Y2M3D");
        System.out.println("Parsed from string: " + parsed);
    }
}

此示例演示了创建 Period 对象的不同方法。输出以 ISO-8601 格式 (P1Y2M3D) 显示 Period。 between 方法计算两个日期之间的确切 Period。

获取 Period 组件

一个 Period 可以分解为它的年、月和日组件。这些值表示 Period 的各个部分。这些方法对于显示或进一步计算特定组件非常有用。

Main.java
package com.zetcode; 

import java.time.Period;

public class Main {

    public static void main(String[] args) {

        Period period = Period.of(2, 5, 10);
        
        // Get individual components
        int years = period.getYears();
        int months = period.getMonths();
        int days = period.getDays();
        
        System.out.println("Years: " + years);
        System.out.println("Months: " + months);
        System.out.println("Days: " + days);
        
        // Check if zero or negative
        System.out.println("Is zero: " + period.isZero());
        System.out.println("Is negative: " + period.isNegative());
        
        // Normalized form
        Period normalized = period.normalized();
        System.out.println("Normalized: " + normalized);
    }
}

此示例演示了如何从 Period 中提取组件。 normalized 方法通过将多余的月份转换为年,确保月份在 0-11 之间。负的 Period 表示时间向后移动。

加减 Period

可以使用 plusminus 方法将 Period 添加到日期或从日期中减去。这些操作考虑了不同的月份长度和闰年。计算是日历感知的。

Main.java
package com.zetcode; 

import java.time.Period;
import java.time.LocalDate;

public class Main {

    public static void main(String[] args) {

        LocalDate date = LocalDate.of(2025, 1, 15);
        Period period = Period.of(1, 2, 3);
        
        // Add period to date
        LocalDate future = date.plus(period);
        System.out.println("Future date: " + future);
        
        // Subtract period from date
        LocalDate past = date.minus(period);
        System.out.println("Past date: " + past);
        
        // Add periods together
        Period another = Period.of(0, 3, 10);
        Period combined = period.plus(another);
        System.out.println("Combined period: " + combined);
        
        // Subtract periods
        Period difference = period.minus(another);
        System.out.println("Difference: " + difference);
    }
}

此示例演示了使用 Period 执行算术的各种方法。当添加到日期时,Period 会自动处理月份长度变化。 Period 算术分别保留每个组件。

比较 Period

可以比较 Period 是否相等或检查其零/负值。请注意,比较方法不会在组件之间进行转换(1 个月 ≠ 30 天)。该类提供了用于基本 Period 分析的方法。

Main.java
package com.zetcode; 

import java.time.Period;

public class Main {

    public static void main(String[] args) {

        Period period1 = Period.of(1, 2, 3);
        Period period2 = Period.of(0, 14, 3);
        Period period3 = Period.of(1, 2, 3);
        
        // Equality checks
        System.out.println("Period1 equals period2: " + period1.equals(period2));
        System.out.println("Period1 equals period3: " + period1.equals(period3));
        
        // Zero and negative checks
        System.out.println("Period1 is zero: " + period1.isZero());
        System.out.println("Period1 is negative: " + period1.isNegative());
        
        // Normalized comparison
        System.out.println("Normalized equals: " + 
            period1.normalized().equals(period2.normalized()));
    }
}

此示例显示了比较 Period 对象的各种方法。请注意,除非进行规范化,否则 14 个月不被认为等于 1 年零 2 个月。负的 Period 表示时间向后移动。

计算年龄

Period 的一个常见用途是计算年龄或日期之间的时间跨度。 between 方法以年、月和日为单位提供精确的计算。这对于生日计算非常有用。

Main.java
package com.zetcode; 

import java.time.Period;
import java.time.LocalDate;
import java.time.Month;

public class Main {

    public static void main(String[] args) {

        LocalDate birthDate = LocalDate.of(1990, Month.MAY, 15);
        LocalDate currentDate = LocalDate.now();
        
        // Calculate age
        Period age = Period.between(birthDate, currentDate);
        System.out.printf("Age: %d years, %d months, %d days%n",
            age.getYears(), age.getMonths(), age.getDays());
        
        // Future date calculation
        LocalDate futureDate = currentDate.plus(Period.ofYears(5));
        Period untilFuture = Period.between(currentDate, futureDate);
        System.out.println("Until future date: " + untilFuture);
        
        // Specific event calculation
        LocalDate eventDate = LocalDate.of(2025, Month.DECEMBER, 25);
        Period untilEvent = Period.between(currentDate, eventDate);
        System.out.println("Until event: " + untilEvent);
    }
}

此示例演示了计算年龄和日期之间的时间跨度。 between 方法提供了精确的结果,考虑了闰年和不同的月份长度。输出显示了人类可读的时长。

Period 解析和格式化

Period 支持 ISO-8601 格式进行解析,并且可以转换为字符串。格式为 PnYnMnD,其中 n 是年、月或日的数量。这对于序列化和配置很有用。

Main.java
package com.zetcode; 

import java.time.Period;

public class Main {

    public static void main(String[] args) {

        // Parsing ISO-8601 format
        Period p1 = Period.parse("P1Y");
        System.out.println("1 year: " + p1);
        
        Period p2 = Period.parse("P2M");
        System.out.println("2 months: " + p2);
        
        Period p3 = Period.parse("P3D");
        System.out.println("3 days: " + p3);
        
        Period p4 = Period.parse("P1Y2M3D");
        System.out.println("1Y2M3D: " + p4);
        
        Period p5 = Period.parse("P-1Y2M");
        System.out.println("Negative 1Y2M: " + p5);
        
        // Converting to string
        String periodStr = p4.toString();
        System.out.println("As string: " + periodStr);
    }
}

此示例显示了从字符串解析 Period 并将其转换回来的过程。 ISO-8601 格式是严格的 - 组件必须按顺序排列(年、月、日)。每个组件都支持负值。

来源

Java Period 类文档

在本文中,我们介绍了 Java Period 类的基本方法和特性。理解这些概念对于在 Java 应用程序中进行准确的基于日期的计算至关重要。

作者

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

列出所有Java教程