1. 概述
本文将快速介绍Java中的TemporalAdjuster
,并通过几个实用场景演示其用法。
Java 8引入了全新的日期时间库java.time
,TemporalAdjuster
是其中重要组成部分。如果想了解java.time
的更多细节,可参考这篇入门文章。
简单来说,TemporalAdjuster
是一种用于调整Temporal
对象的策略模式实现。在深入用法前,我们先了解Temporal
接口本身。
2. Temporal接口
Temporal
表示日期、时间或二者组合的抽象表示,具体取决于实现类。常见实现包括:
✅ LocalDate
– 不带时区的日期
✅ LocalDateTime
– 不带时区的日期时间
✅ HijrahDate
– 伊斯兰历日期
✅ MinguoDate
– 民国历日期
✅ ThaiBuddhistDate
– 泰国佛历日期
3. TemporalAdjuster接口
TemporalAdjuster
是java.time
库中的函数式接口,在TemporalAdjusters
工具类中提供了大量预定义实现。其核心方法是adjustInto()
,通过传入Temporal
对象执行调整操作。
TemporalAdjuster
特别适合处理复杂日期计算,比如:
- 下个星期日的日期
- 当前月份最后一天
- 下一年第一天
虽然用老版java.util.Calendar
也能实现,但新API通过预定义实现封装了底层逻辑。详情可查阅Javadoc。
4. 预定义的TemporalAdjusters
TemporalAdjusters
类提供大量静态方法,返回能以不同方式调整Temporal
对象的TemporalAdjuster
实例。核心方法包括:
⚠️ 常用调整器列表:
dayOfWeekInMonth()
– 月内第几个星期几(如三月第二个星期二)firstDayOfMonth()
– 当月第一天firstDayOfNextMonth()
– 下个月第一天firstDayOfNextYear()
– 下一年第一天firstDayOfYear()
– 当年第一天lastDayOfMonth()
– 当月最后一天nextOrSame()
– 下一个指定星期几(如果当天匹配则返回当天)
方法名基本自解释,完整列表见Javadoc。
举个栗子:获取2017-07-08之后的下一个星期日(测试用固定日期避免时间变化):
@Test
public void whenAdjust_thenNextSunday() {
LocalDate localDate = LocalDate.of(2017, 07, 8);
LocalDate nextSunday = localDate.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
String expected = "2017-07-09";
assertEquals(expected, nextSunday.toString());
}
获取当月最后一天:
LocalDate lastDayOfMonth = localDate.with(TemporalAdjusters.lastDayOfMonth());
5. 自定义TemporalAdjuster实现
可通过两种方式创建自定义调整器:
5.1. 使用Lambda表达式
计算14天后的日期:
@Test
public void whenAdjust_thenFourteenDaysAfterDate() {
LocalDate localDate = LocalDate.of(2017, 07, 8);
TemporalAdjuster temporalAdjuster = t -> t.plus(Period.ofDays(14));
LocalDate result = localDate.with(temporalAdjuster);
String fourteenDaysAfterDate = "2017-07-22";
assertEquals(fourteenDaysAfterDate, result.toString());
}
⚠️ 工作日计算器:获取下个工作日(跳过周末):
static TemporalAdjuster NEXT_WORKING_DAY = TemporalAdjusters.ofDateAdjuster(date -> {
DayOfWeek dayOfWeek = date.getDayOfWeek();
int daysToAdd;
if (dayOfWeek == DayOfWeek.FRIDAY)
daysToAdd = 3; // 周五+3天=周一
else if (dayOfWeek == DayOfWeek.SATURDAY)
daysToAdd = 2; // 周六+2天=周一
else
daysToAdd = 1; // 其他+1天
return date.plusDays(daysToAdd);
});
测试代码:
@Test
public void whenAdjust_thenNextWorkingDay() {
LocalDate localDate = LocalDate.of(2017, 07, 8); // 周六
TemporalAdjuster temporalAdjuster = NEXT_WORKING_DAY;
LocalDate result = localDate.with(temporalAdjuster);
assertEquals("2017-07-10", result.toString()); // 应为周一
}
5.2. 实现TemporalAdjuster接口
创建自定义类实现TemporalAdjuster
接口:
public class CustomTemporalAdjuster implements TemporalAdjuster {
@Override
public Temporal adjustInto(Temporal temporal) {
DayOfWeek dayOfWeek
= DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
int daysToAdd;
if (dayOfWeek == DayOfWeek.FRIDAY)
daysToAdd = 3;
else if (dayOfWeek == DayOfWeek.SATURDAY)
daysToAdd = 2;
else
daysToAdd = 1;
return temporal.plus(daysToAdd, ChronoUnit.DAYS);
}
}
测试实现:
@Test
public void whenAdjustAndImplementInterface_thenNextWorkingDay() {
LocalDate localDate = LocalDate.of(2017, 07, 8);
CustomTemporalAdjuster temporalAdjuster = new CustomTemporalAdjuster();
LocalDate nextWorkingDay = localDate.with(temporalAdjuster);
assertEquals("2017-07-10", nextWorkingDay.toString());
}
6. 总结
本文介绍了TemporalAdjuster
的核心概念、预定义调整器的使用,以及两种自定义实现方式(Lambda表达式和接口实现)。在实际开发中,合理利用这些工具可以简单粗暴地解决各种日期计算需求,避免重复造轮子。
完整代码示例可在GitHub仓库查看。