ZetCode

Java TemporalAmount 接口

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

java.time.temporal.TemporalAmount 接口表示一段时间。它可用于定义诸如“2 小时”或“5 天”之类的量。此接口由 Duration 和 Period 等类实现。

TemporalAmount 提供了从时间对象中添加或减去时间量的方法。它同时适用于基于日期和基于时间的时间量。该接口是 Java 8 中引入的 Java 现代日期时间 API 的一部分。

TemporalAmount 接口概述

TemporalAmount 接口定义了时间操作的方法。关键实现是 Duration(基于时间)和 Period(基于日期)。该接口支持跨不同时间类型进行灵活的时间计算。

public interface TemporalAmount {
    long get(TemporalUnit unit);
    List<TemporalUnit> getUnits();
    Temporal addTo(Temporal temporal);
    Temporal subtractFrom(Temporal temporal);
}

上面的代码显示了 TemporalAmount 定义的方法。这些方法允许查询单位、获取值和执行时间算术运算。实现必须处理单位转换和边界条件。

将 Duration 与 TemporalAmount 一起使用

Duration 是 TemporalAmount 的一个基于时间的实现。它表示以秒和纳秒为单位的一段时间。Duration 非常适合精确的时间测量。

Main.java
package com.zetcode;

import java.time.Duration;
import java.time.LocalTime;

public class Main {

    public static void main(String[] args) {
        
        Duration duration = Duration.ofHours(2).plusMinutes(30);
        
        // Get units
        System.out.println("Units: " + duration.getUnits());
        
        // Get value in seconds
        System.out.println("Seconds: " + duration.getSeconds());
        
        // Add to temporal object
        LocalTime time = LocalTime.of(10, 0);
        LocalTime newTime = (LocalTime) duration.addTo(time);
        System.out.println("New time: " + newTime);
        
        // Subtract from temporal object
        LocalTime earlierTime = (LocalTime) duration.subtractFrom(time);
        System.out.println("Earlier time: " + earlierTime);
    }
}

此示例演示了将 Duration 用作 TemporalAmount。我们创建一个 2.5 小时的持续时间,然后将其添加到 LocalTime 并从中减去。getUnits() 方法显示持续时间包含哪些时间单位。

将 Period 与 TemporalAmount 一起使用

Period 是 TemporalAmount 的一个基于日期的实现。它表示以年、月和天为单位的一段时间。Period 适用于基于日历的日期计算。

Main.java
package com.zetcode;

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

public class Main {

    public static void main(String[] args) {
        
        Period period = Period.ofYears(1).plusMonths(2).plusDays(3);
        
        // Get units
        System.out.println("Units: " + period.getUnits());
        
        // Get values
        System.out.println("Years: " + period.getYears());
        System.out.println("Months: " + period.getMonths());
        System.out.println("Days: " + period.getDays());
        
        // Add to temporal object
        LocalDate date = LocalDate.of(2025, 1, 1);
        LocalDate newDate = (LocalDate) period.addTo(date);
        System.out.println("New date: " + newDate);
    }
}

此示例显示了 Period 被用作 TemporalAmount。我们创建一个 1 年 2 个月 3 天的 Period,然后将其添加到 LocalDate。Period 自动处理日历感知日期算术。

自定义 TemporalAmount 实现

我们可以创建 TemporalAmount 的自定义实现,用于专门的时间计算。此示例显示了一个简单的实现,仅代表工作日。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
import java.util.Collections;
import java.util.List;

public class Main {

    static class BusinessDays implements TemporalAmount {
        private final long days;

        public BusinessDays(long days) {
            this.days = days;
        }

        @Override
        public Temporal addTo(Temporal temporal) {
            LocalDate date = LocalDate.from(temporal);
            long added = 0;
            while (added < days) {
                date = date.plus(1, ChronoUnit.DAYS);
                if (date.getDayOfWeek().getValue() < 6) {
                    added++;
                }
            }
            return temporal.with(date);
        }

        @Override
        public Temporal subtractFrom(Temporal temporal) {
            return addTo(temporal).minus(days * 2, ChronoUnit.DAYS);
        }

        @Override
        public long get(TemporalUnit unit) {
            if (unit == ChronoUnit.DAYS) {
                return days;
            }
            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
        }

        @Override
        public List getUnits() {
            return Collections.singletonList(ChronoUnit.DAYS);
        }
    }

    public static void main(String[] args) {
        BusinessDays businessDays = new BusinessDays(5);
        LocalDate startDate = LocalDate.of(2025, 4, 1); // Tuesday
        
        LocalDate endDate = (LocalDate) businessDays.addTo(startDate);
        System.out.println("Start date: " + startDate);
        System.out.println("End date (5 business days later): " + endDate);
    }
}

此示例演示了一个自定义 TemporalAmount,它跳过周末。BusinessDays 类在执行日期算术时仅添加工作日。这展示了如何为业务应用程序创建专门的时间计算。

组合 TemporalAmount 实现

我们可以组合不同的 TemporalAmount 实现以进行复杂的时间计算。此示例混合了 Period 和 Duration 以获得完整的时间跨度。

Main.java
package com.zetcode;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.temporal.TemporalAmount;

public class Main {

    public static void main(String[] args) {
        // Date-based amount
        Period period = Period.of(1, 2, 3); // 1 year, 2 months, 3 days
        
        // Time-based amount
        Duration duration = Duration.ofHours(4).plusMinutes(30);
        
        LocalDateTime dateTime = LocalDateTime.of(2025, 1, 1, 10, 0);
        System.out.println("Original: " + dateTime);
        
        // Apply period first (date-based)
        LocalDateTime afterPeriod = (LocalDateTime) period.addTo(dateTime);
        System.out.println("After period: " + afterPeriod);
        
        // Then apply duration (time-based)
        LocalDateTime afterBoth = (LocalDateTime) duration.addTo(afterPeriod);
        System.out.println("After both: " + afterBoth);
        
        // Combined operation
        LocalDateTime combined = dateTime
            .plus(period)
            .plus(duration);
        System.out.println("Combined result: " + combined);
    }
}

此示例显示了如何组合 Period 和 Duration 操作。我们首先添加一个 Period(基于日期),然后添加一个 Duration(基于时间)到 LocalDateTime。结果演示了使用多个 TemporalAmounts 的复杂时间算术运算。

查询 TemporalAmount 值

TemporalAmount 接口提供了查询其组成值的方法。此示例显示了如何检查不同时间量的单位和值。

Main.java
package com.zetcode;

import java.time.Duration;
import java.time.Period;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;

public class Main {

    public static void main(String[] args) {
        TemporalAmount[] amounts = {
            Period.of(1, 2, 3),
            Duration.ofHours(2).plusMinutes(30),
            Duration.ofDays(1).plusHours(6)
        };
        
        for (TemporalAmount amount : amounts) {
            System.out.println("\nAmount: " + amount);
            System.out.println("Units: " + amount.getUnits());
            
            for (TemporalUnit unit : amount.getUnits()) {
                System.out.println(unit + ": " + amount.get(unit));
            }
        }
        
        // Custom query for specific unit
        Duration duration = Duration.ofMinutes(90);
        long hours = duration.get(ChronoUnit.HOURS);
        long minutes = duration.get(ChronoUnit.MINUTES);
        System.out.println("\n90 minutes = " + hours + " hours " + 
            (minutes - hours * 60) + " minutes");
    }
}

此示例演示了如何查询 TemporalAmount 对象的组成部分。我们检查 Period 和 Duration 实例,显示它们的单位和值。get() 方法允许从量中访问特定的单位值。

将 TemporalAmount 与 TemporalAdjuster 一起使用

TemporalAmount 可与 TemporalAdjuster 一起使用,以进行更复杂的日期操作。此示例显示了组合这些接口以进行灵活的日期计算。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAmount;

public class Main {

    static class NextBusinessDayAdjuster implements TemporalAdjuster {
        private final TemporalAmount amount;
        
        public NextBusinessDayAdjuster(TemporalAmount amount) {
            this.amount = amount;
        }
        
        @Override
        public Temporal adjustInto(Temporal temporal) {
            Temporal adjusted = amount.addTo(temporal);
            LocalDate date = LocalDate.from(adjusted);
            
            // Adjust to next business day if needed
            while (date.getDayOfWeek().getValue() >= 6) {
                date = date.plusDays(1);
            }
            return temporal.with(date);
        }
    }

    public static void main(String[] args) {
        TemporalAmount twoDays = Period.ofDays(2);
        TemporalAdjuster adjuster = new NextBusinessDayAdjuster(twoDays);
        
        LocalDate friday = LocalDate.of(2025, 4, 4); // Friday
        LocalDate nextBusinessDay = friday.with(adjuster);
        
        System.out.println("Friday: " + friday);
        System.out.println("Two business days later: " + nextBusinessDay);
        
        // Using with Period
        Period period = Period.ofWeeks(1);
        LocalDate inOneWeek = friday.with(new NextBusinessDayAdjuster(period));
        System.out.println("One business week later: " + inOneWeek);
    }
}

此示例将 TemporalAmount 与 TemporalAdjuster 结合使用,以创建业务日感知的日期计算。调整器确保结果落在工作日,即使添加标准时间量也是如此。这展示了强大的时间操作。

来源

Java TemporalAmount 接口文档

在本文中,我们介绍了 Java TemporalAmount 接口的基本方法和特性。理解这些概念对于在现代 Java 应用程序中灵活地处理时间至关重要。

作者

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

列出所有Java教程