ZetCode

Java TemporalUnit 接口

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

java.time.temporal.TemporalUnit 接口表示一个时间单位。它是 Java 8 中引入的 Java 日期和时间 API 的一部分。TemporalUnit 定义了如何度量和操作时间单位。

TemporalUnitChronoUnit 枚举实现,该枚举提供了标准单位,如秒、分钟、小时、天等。该接口允许创建自定义时间单位。它与时间对象(如 Instant 和 LocalDateTime)一起使用。

TemporalUnit 接口概述

TemporalUnit 接口定义了用于查询和操作时间对象的方法。关键操作包括检查持续时间、添加到时间对象以及估计长度。该接口支持灵活的时间计算。

public interface TemporalUnit {
    Duration getDuration();
    boolean isDurationEstimated();
    boolean isDateBased();
    boolean isTimeBased();
    boolean isSupportedBy(Temporal temporal);
    <R extends Temporal> R addTo(R temporal, long amount);
    long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive);
    String toString();
}

上面的代码显示了 TemporalUnit 的关键方法。这些方法允许查询单位特征并执行时间算术。该接口是 Java 中基于时间计算的基础。

使用 ChronoUnit 常量

ChronoUnit 枚举提供了 TemporalUnit 的标准实现。这些常量表示常见的的时间单位,从纳秒到世纪。它们是使用 TemporalUnit 的最常见方式。

Main.java
package com.zetcode;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

public class Main {

    public static void main(String[] args) {
        
        LocalDateTime now = LocalDateTime.now();
        
        // Add 5 hours
        LocalDateTime later = now.plus(5, ChronoUnit.HOURS);
        System.out.println("5 hours later: " + later);
        
        // Subtract 3 days
        LocalDateTime earlier = now.minus(3, ChronoUnit.DAYS);
        System.out.println("3 days earlier: " + earlier);
        
        // Check if time-based
        System.out.println("Is DAYS time-based? " + ChronoUnit.DAYS.isTimeBased());
        
        // Check if date-based
        System.out.println("Is HOURS date-based? " + ChronoUnit.HOURS.isDateBased());
    }
}

此示例演示了将 ChronoUnit 常量与 LocalDateTime 一起使用。plusminus 方法接受 TemporalUnit 参数。ChronoUnit 提供了基于时间和基于日期的单位。

检查单位特性

TemporalUnit 提供了检查单位属性的方法。这些包括一个单位是基于时间的、基于日期的,还是具有估计的持续时间。此信息对于验证和条件逻辑很有用。

Main.java
package com.zetcode;

import java.time.temporal.ChronoUnit;

public class Main {

    public static void main(String[] args) {
        
        // Check unit characteristics
        System.out.println("NANOS duration: " + ChronoUnit.NANOS.getDuration());
        System.out.println("Is YEARS estimated? " + ChronoUnit.YEARS.isDurationEstimated());
        
        // Time-based vs date-based
        System.out.println("SECONDS isTimeBased: " + ChronoUnit.SECONDS.isTimeBased());
        System.out.println("MONTHS isDateBased: " + ChronoUnit.MONTHS.isDateBased());
        
        // Mixed units
        System.out.println("WEEKS isTimeBased: " + ChronoUnit.WEEKS.isTimeBased());
        System.out.println("WEEKS isDateBased: " + ChronoUnit.WEEKS.isDateBased());
    }
}

此示例展示了如何查询 TemporalUnit 的特征。请注意,有些单位(如 WEEKS)既不是基于时间也不是基于日期的。基于日期的单位的持续时间可能由于月份长度的变化而有所估计。

计算日期之间的时间

between 方法以特定单位计算两个时间对象之间的时间。这对于以不同单位测量持续时间很有用。计算会尊重日历规则(如果适用)。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;

public class Main {

    public static void main(String[] args) {
        
        LocalDate date1 = LocalDate.of(2025, 1, 1);
        LocalDate date2 = LocalDate.of(2025, 6, 15);
        
        // Calculate difference in days
        long daysBetween = ChronoUnit.DAYS.between(date1, date2);
        System.out.println("Days between: " + daysBetween);
        
        // Calculate difference in months
        long monthsBetween = ChronoUnit.MONTHS.between(date1, date2);
        System.out.println("Months between: " + monthsBetween);
        
        LocalTime time1 = LocalTime.of(8, 30);
        LocalTime time2 = LocalTime.of(14, 45);
        
        // Calculate difference in hours
        double hoursBetween = ChronoUnit.HOURS.between(time1, time2);
        System.out.println("Hours between: " + hoursBetween);
    }
}

此示例演示了使用 TemporalUnit 计算时间差。between 方法以指定的单位返回数量。对于基于日期的单位,计算会考虑日历规则。

创建自定义 TemporalUnit

虽然 ChronoUnit 涵盖了大多数需求,但您可以为自定义时间单位实现 TemporalUnit。这需要实现所有接口方法。该示例显示了一个简单的工作周单位。

Main.java
package com.zetcode;

import java.time.Duration;
import java.time.LocalDate;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalUnit;
import java.util.List;

public class Main {

    static class WorkWeekUnit implements TemporalUnit {
        
        @Override
        public Duration getDuration() {
            return Duration.ofDays(5);
        }
        
        @Override
        public boolean isDurationEstimated() {
            return false;
        }
        
        @Override
        public boolean isDateBased() {
            return true;
        }
        
        @Override
        public boolean isTimeBased() {
            return false;
        }
        
        @Override
        public boolean isSupportedBy(Temporal temporal) {
            return temporal.isSupported(ChronoUnit.DAYS);
        }
        
        @Override
        public Temporal addTo(Temporal temporal, long amount) {
            return temporal.plus(amount * 5, ChronoUnit.DAYS);
        }
        
        @Override
        public long between(Temporal temporal1, Temporal temporal2) {
            return ChronoUnit.DAYS.between(temporal1, temporal2) / 5;
        }
        
        @Override
        public String toString() {
            return "WorkWeek";
        }
    }

    public static void main(String[] args) {
        
        WorkWeekUnit workWeek = new WorkWeekUnit();
        LocalDate startDate = LocalDate.of(2025, 1, 1);
        
        // Add 2 work weeks
        LocalDate endDate = (LocalDate) workWeek.addTo(startDate, 2);
        System.out.println("After 2 work weeks: " + endDate);
        
        // Calculate work weeks between
        long weeks = workWeek.between(startDate, endDate);
        System.out.println("Work weeks between: " + weeks);
    }
}

此示例显示了自定义 WorkWeekUnit 的实现。该单位将 5 天视为一个工作周。所有 TemporalUnit 方法都已实现以支持此自定义时间度量。

将 TemporalUnit 与 Duration 结合使用

TemporalUnit 与 Duration 配合使用,可以进行精确的时间计算。Duration 可以从 TemporalUnit 的 getDuration 方法创建。这支持基于时间的灵活操作。

Main.java
package com.zetcode;

import java.time.Duration;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;

public class Main {

    public static void main(String[] args) {
        
        // Get duration of different units
        Duration hourDuration = ChronoUnit.HOURS.getDuration();
        System.out.println("Duration of HOURS: " + hourDuration);
        
        Duration dayDuration = ChronoUnit.DAYS.getDuration();
        System.out.println("Duration of DAYS: " + dayDuration);
        
        // Use with LocalTime
        LocalTime time = LocalTime.of(9, 0);
        LocalTime newTime = time.plus(hourDuration.multipliedBy(3));
        System.out.println("Time after 3 hours: " + newTime);
        
        // Compare durations
        System.out.println("Is HOURS shorter than DAYS? " + 
            (hourDuration.compareTo(dayDuration) < 0));
    }
}

此示例演示了 TemporalUnit 和 Duration 之间的关系。getDuration 方法提供了一个单位的标准持续时间。持续时间可以直接用于时间计算中。

验证单位支持

并非所有时间对象都支持所有单位。isSupportedBy 方法检查一个单位是否可以与特定的时间对象一起使用。这可以防止出现不支持的操作异常。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;

public class Main {

    public static void main(String[] args) {
        
        LocalDate date = LocalDate.now();
        LocalTime time = LocalTime.now();
        
        // Check date support
        System.out.println("MONTHS supported by date: " + 
            ChronoUnit.MONTHS.isSupportedBy(date));
        System.out.println("HOURS supported by date: " + 
            ChronoUnit.HOURS.isSupportedBy(date));
        
        // Check time support
        System.out.println("SECONDS supported by time: " + 
            ChronoUnit.SECONDS.isSupportedBy(time));
        System.out.println("DAYS supported by time: " + 
            ChronoUnit.DAYS.isSupportedBy(time));
        
        // Try to use unsupported unit
        if (ChronoUnit.YEARS.isSupportedBy(time)) {
            time = time.plus(1, ChronoUnit.YEARS);
        } else {
            System.out.println("Cannot add YEARS to LocalTime");
        }
    }
}

此示例显示了如何在执行操作之前检查单位支持。LocalDate 支持基于日期的单位,而 LocalTime 支持基于时间的单位。此检查可防止尝试使用不兼容的单位。

来源

Java TemporalUnit 接口文档

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

作者

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

列出所有Java教程