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教程。