Java TemporalAdjuster 接口
最后修改时间:2025 年 4 月 16 日
java.time.temporal.TemporalAdjuster
接口提供灵活的日期调整功能。 它允许进行超出简单加/减操作的复杂日期操作。 实现可以找到下一个或上一个星期几。
TemporalAdjuster
是一个只有一个方法的函数式接口。 它适用于 java.time 包中的所有时间类型。 TemporalAdjusters
实用程序类提供了常见的调整。
TemporalAdjuster 接口概述
该接口定义了一个方法 adjustInto
,它接受一个时间对象并返回一个调整后的版本。 TemporalAdjusters
类提供了许多预定义的调整器。 自定义调整器可以实现复杂的逻辑。
public interface TemporalAdjuster { Temporal adjustInto(Temporal temporal); } public final class TemporalAdjusters { public static TemporalAdjuster firstDayOfMonth(); public static TemporalAdjuster lastDayOfMonth(); public static TemporalAdjuster firstDayOfNextMonth(); public static TemporalAdjuster firstDayOfYear(); public static TemporalAdjuster lastDayOfYear(); public static TemporalAdjuster firstDayOfNextYear(); public static TemporalAdjuster next(DayOfWeek dayOfWeek); public static TemporalAdjuster nextOrSame(DayOfWeek dayOfWeek); public static TemporalAdjuster previous(DayOfWeek dayOfWeek); public static TemporalAdjuster previousOrSame(DayOfWeek dayOfWeek); }
代码显示了 TemporalAdjusters
中的接口和关键方法。 这些提供了常见的日期调整,例如查找月份边界或特定的工作日。 调整器是线程安全的且不可变的。
使用预定义的调整器
TemporalAdjusters
类提供了许多有用的调整器。 这些处理常见情况,例如查找月份边界或特定的工作日。 它们可以与支持调整的任何时间类型一起使用。
package com.zetcode; import java.time.LocalDate; import java.time.Month; import java.time.temporal.TemporalAdjusters; import java.time.DayOfWeek; public class Main { public static void main(String[] args) { LocalDate date = LocalDate.of(2025, Month.APRIL, 15); // First day of month LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth()); System.out.println("First day of month: " + firstDay); // Last day of month LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth()); System.out.println("Last day of month: " + lastDay); // Next Tuesday LocalDate nextTuesday = date.with(TemporalAdjusters.next(DayOfWeek.TUESDAY)); System.out.println("Next Tuesday: " + nextTuesday); // First day of next year LocalDate firstNextYear = date.with(TemporalAdjusters.firstDayOfNextYear()); System.out.println("First day of next year: " + firstNextYear); } }
此示例演示了几个预定义的调整器。 每个调整都会创建一个新的日期对象,而不会修改原始对象。 调整器会自动处理边缘情况,例如月份长度变化。
查找工作日
TemporalAdjusters 提供了查找相对于日期的特定工作日的方法。 这些包括下一个、上一个和同一天变体。 它们对于安排重复发生的事件很有用。
package com.zetcode; import java.time.LocalDate; import java.time.Month; import java.time.temporal.TemporalAdjusters; import java.time.DayOfWeek; public class Main { public static void main(String[] args) { LocalDate date = LocalDate.of(2025, Month.APRIL, 15); // Tuesday // Next Friday LocalDate nextFriday = date.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)); System.out.println("Next Friday: " + nextFriday); // Previous Monday LocalDate prevMonday = date.with(TemporalAdjusters.previous(DayOfWeek.MONDAY)); System.out.println("Previous Monday: " + prevMonday); // Next or same Wednesday LocalDate nextOrSameWed = date.with(TemporalAdjusters.nextOrSame(DayOfWeek.WEDNESDAY)); System.out.println("Next or same Wednesday: " + nextOrSameWed); // Previous or same Friday LocalDate prevOrSameFri = date.with(TemporalAdjusters.previousOrSame(DayOfWeek.FRIDAY)); System.out.println("Previous or same Friday: " + prevOrSameFri); } }
此示例显示了与工作日相关的调整器。 如果当前日期匹配,则 "next" 和 "previous" 方法会排除当前日期。 当 "OrSame" 变体与目标工作日匹配时,它们会包含当前日期。
自定义 Temporal Adjuster
自定义调整器可以实现复杂的日期逻辑。 它们通过实现接口或使用 lambda 表达式来创建。 这为特定于业务的日期规则提供了灵活性。
package com.zetcode; import java.time.LocalDate; import java.time.Month; import java.time.temporal.Temporal; import java.time.temporal.TemporalAdjuster; public class Main { static class NextPaydayAdjuster implements TemporalAdjuster { @Override public Temporal adjustInto(Temporal temporal) { LocalDate date = LocalDate.from(temporal); int day = date.getDayOfMonth(); if (day < 15) { return date.withDayOfMonth(15); } else { return date.withDayOfMonth(date.lengthOfMonth()); } } } public static void main(String[] args) { LocalDate date = LocalDate.of(2025, Month.APRIL, 10); TemporalAdjuster paydayAdjuster = new NextPaydayAdjuster(); // Using class implementation LocalDate nextPayday = date.with(paydayAdjuster); System.out.println("Next payday: " + nextPayday); // Using lambda expression TemporalAdjuster taxDayAdjuster = t -> { LocalDate d = LocalDate.from(t); return d.withMonth(4).withDayOfMonth(15); }; LocalDate taxDay = date.with(taxDayAdjuster); System.out.println("Tax day: " + taxDay); } }
此示例显示了创建自定义调整器的两种方法。 第一个使用实现该接口的类。 第二个使用 lambda 表达式。 两种方法都可以实现所需的任何日期计算逻辑。
组合调整器
可以组合调整器以按顺序执行多个操作。 每个调整都应用于前一个调整的结果。 这允许从简单的步骤构建复杂的日期计算。
package com.zetcode; import java.time.LocalDate; import java.time.Month; import java.time.temporal.TemporalAdjusters; import java.time.DayOfWeek; public class Main { public static void main(String[] args) { LocalDate date = LocalDate.of(2025, Month.APRIL, 15); // First go to first of month, then find next Friday LocalDate result = date.with(TemporalAdjusters.firstDayOfMonth()) .with(TemporalAdjusters.next(DayOfWeek.FRIDAY)); System.out.println("First Friday of month: " + result); // First find next Monday, then go to end of that month LocalDate result2 = date.with(TemporalAdjusters.next(DayOfWeek.MONDAY)) .with(TemporalAdjusters.lastDayOfMonth()); System.out.println("Last day of month containing next Monday: " + result2); // Custom combined adjuster TemporalAdjuster combined = t -> { Temporal temp = TemporalAdjusters.firstDayOfMonth().adjustInto(t); return TemporalAdjusters.next(DayOfWeek.WEDNESDAY).adjustInto(temp); }; LocalDate result3 = date.with(combined); System.out.println("First Wednesday of month: " + result3); } }
此示例演示了以不同方式组合调整器。 前两个示例直接链接调整。 第三个创建了一个组合的调整器作为 lambda。 所有方法都实现了顺序调整的相同目标。
调整时间对象
虽然通常与日期一起使用,但 TemporalAdjusters 也适用于时间对象。 它们可以调整 LocalDateTime、ZonedDateTime 和其他时间类型。 调整逻辑必须与时间类型兼容。
package com.zetcode; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZonedDateTime; import java.time.ZoneId; import java.time.temporal.TemporalAdjusters; import java.time.DayOfWeek; public class Main { public static void main(String[] args) { LocalDateTime dateTime = LocalDateTime.of(2025, 4, 15, 10, 30); // Adjust LocalDateTime LocalDateTime nextMonday = dateTime.with(TemporalAdjusters.next(DayOfWeek.MONDAY)); System.out.println("Next Monday at same time: " + nextMonday); // Adjust ZonedDateTime ZonedDateTime zoned = ZonedDateTime.now(ZoneId.of("America/New_York")); ZonedDateTime lastDay = zoned.with(TemporalAdjusters.lastDayOfMonth()); System.out.println("Last day of month in NY: " + lastDay); // Custom time adjuster TemporalAdjuster toNoon = t -> { if (t.isSupported(ChronoField.HOUR_OF_DAY)) { return t.with(ChronoField.HOUR_OF_DAY, 12) .with(ChronoField.MINUTE_OF_HOUR, 0) .with(ChronoField.SECOND_OF_MINUTE, 0); } return t; }; LocalDateTime noon = dateTime.with(toNoon); System.out.println("Adjusted to noon: " + noon); } }
此示例显示了调整器与不同时间类型一起工作。 自定义时间调整器演示了专门处理时间字段。 请注意在尝试调整之前检查字段支持。
工作日调整器
一个常见的用例是将日期调整为工作日。 这需要跳过周末并可能跳过节假日。 该示例显示了一个基本的工作日调整器实现。
package com.zetcode; import java.time.LocalDate; import java.time.DayOfWeek; import java.time.temporal.Temporal; import java.time.temporal.TemporalAdjuster; import java.time.temporal.ChronoUnit; public class Main { static class BusinessDaysAdjuster implements TemporalAdjuster { private final int days; public BusinessDaysAdjuster(int days) { this.days = days; } @Override public Temporal adjustInto(Temporal temporal) { LocalDate date = LocalDate.from(temporal); int remaining = days; int step = Integer.signum(remaining); while (remaining != 0) { date = date.plus(step, ChronoUnit.DAYS); if (date.getDayOfWeek() != DayOfWeek.SATURDAY && date.getDayOfWeek() != DayOfWeek.SUNDAY) { remaining -= step; } } return temporal.with(date); } } public static void main(String[] args) { LocalDate date = LocalDate.of(2025, 4, 15); // Tuesday TemporalAdjuster add5BusinessDays = new BusinessDaysAdjuster(5); TemporalAdjuster subtract3BusinessDays = new BusinessDaysAdjuster(-3); LocalDate in5Days = date.with(add5BusinessDays); System.out.println("5 business days later: " + in5Days); LocalDate before3Days = date.with(subtract3BusinessDays); System.out.println("3 business days before: " + before3Days); } }
此示例实现了一个跳过周末的工作日调整器。 该调整器适用于向前和向后调整。 更复杂的版本可以合并节假日日历,以进行完整的工作日期计算。
来源
在本文中,我们介绍了 Java TemporalAdjuster 接口的基本方法和功能。 了解这些概念对于现代 Java 应用程序中的复杂日期操作至关重要。
作者
列出所有Java教程。