431. Java 日期时间 API - 时间工具 TemporalAdjuster 详解
大家好,今天我们来聊聊 TemporalAdjuster —— 它是 Java 8 时间 API 中一个很有意思的接口。简单来说,它就是一个 日期调节器,帮我们把一个日期“调整”为另一个日期。
比如:
- 算出下个月的第一天
- 找到这个月的最后一个星期五
- 自动算工资发放日(如果是周末就提前到周五)
是不是很实用?😉
1. 什么是 TemporalAdjuster?
- 所在包:
java.time.temporal - 定义:接收一个 Temporal 对象(比如 LocalDate、ZonedDateTime),然后返回一个“调整过”的新日期。
- 特点:
- 不会修改原始日期(不可变对象)
- 可以用在
with()方法里直接调用
👉 类似于给时间对象装上一个“智能计算器”。
2. 预定义的 Adjusters
Java 已经帮我们准备了很多常见的日期调整器,放在 TemporalAdjusters 工具类里。
常见的有:
-
firstDayOfMonth()→ 本月第一天 -
lastDayOfMonth()→ 本月最后一天 -
firstInMonth(DayOfWeek.MONDAY)→ 本月第一个星期一 -
firstDayOfNextYear()→ 下一年的第一天
示例代码:
import java.time.*;
import java.time.temporal.*;
public class AdjusterDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2000, Month.OCTOBER, 15);
System.out.printf("%s 是星期 %s%n", date, date.getDayOfWeek());
System.out.println("本月第一天: " + date.with(TemporalAdjusters.firstDayOfMonth()));
System.out.println("本月第一个星期一: " + date.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)));
System.out.println("本月最后一天: " + date.with(TemporalAdjusters.lastDayOfMonth()));
System.out.println("下个月第一天: " + date.with(TemporalAdjusters.firstDayOfNextMonth()));
System.out.println("下一年第一天: " + date.with(TemporalAdjusters.firstDayOfNextYear()));
}
}
输出结果:
2000-10-15 是星期 SUNDAY
本月第一天: 2000-10-01
本月第一个星期一: 2000-10-02
本月最后一天: 2000-10-31
下个月第一天: 2000-11-01
下一年第一天: 2001-01-01
👉 看出来了吗?只要一个 with() 就能搞定常见的日期运算,比手写逻辑要简洁很多。
3. 自定义 Adjuster —— 工资日案例 💰
有些规则比较复杂,比如:
- 工资日定在 每月 15 号 和 月底
- 如果碰到周末,提前到星期五
这种情况就要写一个 自定义 Adjuster 了。
实现代码:
import java.time.*;
import java.time.temporal.*;
public class PaydayAdjuster implements TemporalAdjuster {
@Override
public Temporal adjustInto(Temporal input) {
LocalDate date = LocalDate.from(input);
int day;
// 如果今天还没到 15 号,那下一个发薪日就是 15 号
if (date.getDayOfMonth() < 15) {
day = 15;
} else { // 否则就是月底
day = date.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
}
date = date.withDayOfMonth(day);
// 如果发薪日是周六或周日,提前到周五
if (date.getDayOfWeek() == DayOfWeek.SATURDAY ||
date.getDayOfWeek() == DayOfWeek.SUNDAY) {
date = date.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
}
return date;
}
}
使用方式:
public class PaydayTest {
public static void main(String[] args) {
LocalDate d1 = LocalDate.of(2013, 6, 3);
LocalDate d2 = LocalDate.of(2013, 6, 18);
LocalDate nextPayday1 = d1.with(new PaydayAdjuster());
LocalDate nextPayday2 = d2.with(new PaydayAdjuster());
System.out.println("日期: " + d1 + " → 下个发薪日: " + nextPayday1);
System.out.println("日期: " + d2 + " → 下个发薪日: " + nextPayday2);
}
}
输出结果:
日期: 2013-06-03 → 下个发薪日: 2013-06-14
日期: 2013-06-18 → 下个发薪日: 2013-06-28
👉 我们看到,6 月 15 和 30 号都刚好是周末,自动提前到了周五,非常智能!🎯
4. 总结 🎓
-
TemporalAdjuster= 日期调节器 -
TemporalAdjusters= 官方预设的工具箱(第一天、最后一天、下个月…) - 自定义 Adjuster 可以解决企业级的复杂需求(例如工资日、报表日、结算日等)
- 使用方式统一:
date.with(adjuster),保持代码简洁。