ZetCode

Java Temporal 接口

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

java.time.temporal.Temporal 接口是一个框架级接口,用于表示日期时间对象。它提供了对日期时间字段的访问,并允许进行日期时间运算。像 LocalDate 和 ZonedDateTime 这样的类实现了这个接口。

Temporal 定义了查询和操作时间对象的操作。它支持添加或减去时间单位、比较日期以及访问时间字段。该接口支持对不同日期时间类型的多态处理。

Temporal 接口概述

Temporal 接口提供了用于时间算术和字段访问的方法。关键操作包括添加/减去时间、查询字段和调整值。它与 TemporalUnit 和 TemporalField 配合使用,以实现灵活的操作。

public interface Temporal extends TemporalAccessor {
    boolean isSupported(TemporalUnit unit);
    Temporal with(TemporalField field, long newValue);
    Temporal plus(long amountToAdd, TemporalUnit unit);
    Temporal minus(long amountToSubtract, TemporalUnit unit);
    long until(Temporal endExclusive, TemporalUnit unit);
}

以上代码展示了 Temporal 接口的关键方法。这些方法可以操作时间对象,同时保持不可变性。实现类为这些操作提供了具体行为。

基本的时间操作

此示例演示了通过 Temporal 接口可用的基本操作。我们将使用实现 Temporal 的 LocalDate 来展示常见方法。操作包括添加时间和查询字段。

Main.java
package com.zetcode;

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

public class Main {

    public static void main(String[] args) {
        
        LocalDate date = LocalDate.of(2025, 4, 15);
        
        // Add 2 weeks
        Temporal futureDate = date.plus(2, ChronoUnit.WEEKS);
        System.out.println("Date in 2 weeks: " + futureDate);
        
        // Subtract 3 months
        Temporal pastDate = date.minus(3, ChronoUnit.MONTHS);
        System.out.println("Date 3 months ago: " + pastDate);
        
        // Check if unit is supported
        boolean supported = date.isSupported(ChronoUnit.DAYS);
        System.out.println("Days supported: " + supported);
    }
}

此示例展示了使用 LocalDate 的基本 Temporal 操作。plus 和 minus 方法返回新的 Temporal 对象。isSupported 方法检查时间单位是否可与时间对象一起使用。

使用 Temporal 进行字段调整

Temporal 接口允许修改日期时间对象的特定字段。这可以使用 with 方法完成,该方法返回一个新的调整后的对象。字段调整是精确的,并自动处理边缘情况。

Main.java
package com.zetcode;

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

public class Main {

    public static void main(String[] args) {
        
        LocalDateTime dateTime = LocalDateTime.now();
        System.out.println("Original: " + dateTime);
        
        // Change year
        Temporal newYear = dateTime.with(ChronoField.YEAR, 2030);
        System.out.println("Year changed: " + newYear);
        
        // Change hour
        Temporal newHour = dateTime.with(ChronoField.HOUR_OF_DAY, 15);
        System.out.println("Hour changed: " + newHour);
        
        // Chain adjustments
        Temporal adjusted = dateTime
            .with(ChronoField.MONTH_OF_YEAR, 12)
            .with(ChronoField.DAY_OF_MONTH, 25);
        System.out.println("Christmas date: " + adjusted);
    }
}

此示例演示了使用 Temporal 接口的字段调整。每个 with 操作都返回一个新的 Temporal 对象。多个调整可以链接在一起以创建复杂的转换。

计算 Temporal 之间的时间

until 方法以指定的单位计算两个时间对象之间的时间。这对于确定日期或时间之间的持续时间很有用。该方法会自动处理不同的时间类型。

Main.java
package com.zetcode;

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

public class Main {

    public static void main(String[] args) {
        
        LocalDate today = LocalDate.now();
        LocalDate futureDate = today.plusMonths(3).plusDays(5);
        
        // Days between dates
        long daysBetween = today.until(futureDate, ChronoUnit.DAYS);
        System.out.println("Days between: " + daysBetween);
        
        // Months between dates
        long monthsBetween = today.until(futureDate, ChronoUnit.MONTHS);
        System.out.println("Months between: " + monthsBetween);
        
        // Mixed types calculation
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime later = now.plusHours(5).plusMinutes(30);
        long minutesBetween = now.until(later, ChronoUnit.MINUTES);
        System.out.println("Minutes between: " + minutesBetween);
    }
}

此示例展示了如何计算时间对象之间的时间。until 方法适用于不同的时间类型和单位。请注意,计算是精确的,并遵守日历规则。

Temporal 与 TemporalAdjuster

Temporal 对象可以与 TemporalAdjusters 一起使用,以进行复杂的日期调整。调整器提供了预构建的操作,例如“下个星期二”或“当月最后一天”。这演示了 Temporal 接口的灵活性。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.DayOfWeek;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjusters;

public class Main {

    public static void main(String[] args) {
        
        LocalDate date = LocalDate.of(2025, 4, 15);
        
        // Next Friday
        Temporal nextFriday = date.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
        System.out.println("Next Friday: " + nextFriday);
        
        // Last day of month
        Temporal monthEnd = date.with(TemporalAdjusters.lastDayOfMonth());
        System.out.println("Month end: " + monthEnd);
        
        // First day of next year
        Temporal yearStart = date.with(TemporalAdjusters.firstDayOfNextYear());
        System.out.println("Next year start: " + yearStart);
        
        // Custom adjuster (add 2 weeks)
        Temporal custom = date.with(temporal -> temporal.plus(2, ChronoUnit.WEEKS));
        System.out.println("Custom adjusted: " + custom);
    }
}

此示例演示了将 TemporalAdjusters 与 Temporal 对象一起使用。调整器通过函数式接口提供常见的日期操作。也可以使用 lambda 表达式创建自定义调整器。

使用 TemporalQueries

Temporal 对象支持查询以提取信息。query 方法允许从时间对象中灵活地提取数据。这对于通用日期时间处理代码很有用。

Main.java
package com.zetcode;

import java.time.LocalDateTime;
import java.time.temporal.TemporalQueries;
import java.time.temporal.TemporalQuery;

public class Main {

    public static void main(String[] args) {
        
        LocalDateTime dateTime = LocalDateTime.now();
        
        // Query for LocalDate
        TemporalQuery<java.time.LocalDate> dateQuery = TemporalQueries.localDate();
        java.time.LocalDate datePart = dateTime.query(dateQuery);
        System.out.println("Date part: " + datePart);
        
        // Query for time precision
        TemporalQuery<java.time.temporal.ChronoUnit> precisionQuery = 
            TemporalQueries.precision();
        java.time.temporal.ChronoUnit precision = dateTime.query(precisionQuery);
        System.out.println("Precision: " + precision);
        
        // Custom query (get day of week)
        TemporalQuery<String> dayQuery = 
            temporal -> temporal.query(TemporalQueries.localDate())
                               .getDayOfWeek().toString();
        String dayOfWeek = dateTime.query(dayQuery);
        System.out.println("Day of week: " + dayOfWeek);
    }
}

此示例展示了如何查询时间对象以获取信息。内置查询通过 TemporalQueries 提供,并且可以创建自定义查询。query 方法支持对不同时间类型的多态处理。

组合 Temporal 操作

此示例演示了组合多个 Temporal 操作以进行复杂的日期时间计算。我们将链接操作以创建涉及日期计算的业务逻辑场景。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjusters;

public class Main {

    public static void main(String[] args) {
        
        LocalDate projectStart = LocalDate.of(2025, 4, 15);
        
        // Calculate project timeline
        Temporal milestone1 = projectStart
            .plus(2, ChronoUnit.WEEKS)
            .with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
        
        Temporal milestone2 = ((LocalDate) milestone1)
            .plus(3, ChronoUnit.WEEKS)
            .with(TemporalAdjusters.lastDayOfMonth());
        
        Temporal projectEnd = ((LocalDate) milestone2)
            .plus(1, ChronoUnit.MONTHS)
            .with(TemporalAdjusters.dayOfWeekInMonth(3, DayOfWeek.FRIDAY));
        
        System.out.println("Project start: " + projectStart);
        System.out.println("Milestone 1: " + milestone1);
        System.out.println("Milestone 2: " + milestone2);
        System.out.println("Project end: " + projectEnd);
        
        // Calculate total duration
        long totalDays = projectStart.until(projectEnd, ChronoUnit.DAYS);
        System.out.println("Total project days: " + totalDays);
    }
}

此示例结合了多个 Temporal 操作来模拟项目时间线。我们使用 plus 操作、调整器和持续时间计算。请注意,当需要 LocalDate 中的特定方法时,需要进行类型转换。

来源

Java Temporal 接口文档

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

作者

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

列出所有Java教程