文章目录
前言
TemporalAdjuster是Java 8引入的新的处理日期和时间API的一部分。
TemporalAdjuster是时间调节器,可以执行复杂的日期操作,例如,可以获得下一个星期日的日期、当月的最后一天(再也不用计算当月是28,29还是30天了)、下一年的第一天、下一个工作日等等。
一. TemporalAdjuster概述
TemporalAdjuster类是一个函数式接口,是Java 8引入的新的处理日期和时间API的一部分。在TemporalAdjusters类中有许多预定义的实现。
该接口有一个名为adjustInto()的抽象方法,可以通过向其传递Temporal对象在其任何实现中调用它。
TemporalAdjuster允许我们执行复杂的日期操作。比如,获得下个星期日,当月的最后一天或下一年的第一天的日期。
- 包目录:java.time.temporal
- 类型:函数式接口 public interface TemporalAdjuster
- 版本:java8引入
TemporalAdjuster是一种调整Temporal对象的策略,在开始使用TemporalAdjuster之前,让我们先看一下Temporal接口。
二. Temporal 接口
Temporal接口是对时间(Temporal)对象的读写访问的框架级接口。比如日期,时间,偏移或这些的某种组合。
Temporal接口是日期,时间和偏移对象的基本接口类型,定义了对日期的增减操作。
Temporal接口有很多实现,包括:
LocalDate - 表示没有时区的日期 LocalDateTime - 表示没有时区的日期和时间 JapaneseDate - 代表日本日历系统中的日期
三. TemporalAdjusters类中预定义实现
TemporalAdjusters工具类有很多预定义的static方法返回TemporalAdjuster对象,使用不同方式调节Temporal对象而与Temporal实现无关。
| 方法 | 说明 |
|---|---|
| static TemporalAdjuster firstDayOfMonth() | 当前月的第一天 |
| static TemporalAdjuster firstDayOfNextMonth() | 下一个月的第一天 |
| static TemporalAdjuster firstDayOfNextYear() | 下一年的第一天 |
| static TemporalAdjuster firstDayOfYear() | 当年的第一天 |
| static TemporalAdjuster lastDayOfYear() | 当年的最后一天 |
| static TemporalAdjuster lastDayOfMonth() | 当月的最后一天 |
| static TemporalAdjuster firstInMonth(DayOfWeek dayOfWeek) | 某月的第一个星期几 |
| static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) | 某月的最后一个星期几 |
| static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) | 某月的第几个星期几,例如,三月中第二个星期二 |
| static TemporalAdjuster next(DayOfWeek dayOfWeek) | (往后不包括当天)下一个星期几是几月几号。若当前为周三,那么next(DayOfWeek.WEDNESDAY)指下一个周三即下周三;next(DayOfWeek.SUNDAY) 指下一个周日即本周日(此时并不是下周日) |
| static TemporalAdjuster nextOrSame(DayOfWeek dayOfWeek) | (往后包括当天)最近星期几的日期。如最近星期五的日期,如果今天是星期五,则返回今天日期,如果今天不是星期五,则返回下周五的日期 |
| static TemporalAdjuster previous(DayOfWeek dayOfWeek) | (往前不包括当天)上一个星期几是几月几号。若当前为周三,那么previous(DayOfWeek.WEDNESDAY)指上一个周三即上周三;previous(DayOfWeek.TUESDAY) 指上一个周二即昨天(此时并不是上周二) |
| static TemporalAdjuster previousOrSame(DayOfWeek dayOfWeek) | (往前包括当天)最近星期几的日期。如最近星期五的日期,如果今天是星期五,则返回今天日期,如果今天不是星期五,则返回上周五的日期 |
示例:
LocalDate now = LocalDate.now();
System.out.println("当前时间:"+now); //2021-11-30
//获取当月第一天
System.out.println("当月第一天:"+now.with(TemporalAdjusters.firstDayOfMonth()));// 2021-11-01
//获取本月第2天:
System.out.println("本月第2天:"+now.withDayOfMonth(2)); //2021-11-02
//获取下月第一天
System.out.println("下月第一天:"+now.with(TemporalAdjusters.firstDayOfNextMonth())); //2021-12-01
//获取明年第一天
System.out.println("明年第一天:"+now.with(TemporalAdjusters.firstDayOfNextYear())); //2022-01-01
//获取本年第一天
System.out.println("本年第一天:"+now.with(TemporalAdjusters.firstDayOfYear()));//2021-01-01
//获取当月最后一天,再也不用计算是28,29,30还是31:
System.out.println("当月最后一天:"+now.with(TemporalAdjusters.lastDayOfMonth())); //2021-11-30
//获取本年最后一天
System.out.println("本年最后一天:"+now.with(TemporalAdjusters.lastDayOfYear())); //2021-12-31
//获取当月的第一个星期一
System.out.println("当月的第一个星期一:"+now.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY))); //2021-11-01
//获取当月的最后一个星期一
System.out.println("当月的最后一个星期一:"+now.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY))); //2021-11-29
//获取当月第三周星期五
System.out.println("当月第三周星期五:"+now.with(TemporalAdjusters.dayOfWeekInMonth(3, DayOfWeek.FRIDAY))); //2021-11-19
//获取本周一
System.out.println("本周一:"+now.with(DayOfWeek.MONDAY)); //2021-11-29
//获取上周二
System.out.println("上周二:"+now.minusWeeks(1).with(ChronoField.DAY_OF_WEEK, 2)); //2021-11-23
//(往前不包括当天)获取当前日期的上一个周一 如果今天是周一,则返回上周一
System.out.println("上一个周一(不包括当天):"+now.with(TemporalAdjusters.previous(DayOfWeek.MONDAY))); //2021-11-29
//(往前包括当天)最近星期五的日期 如果今天是星期五,则返回今天日期
System.out.println("上一个周一(包括当天):"+now.with(TemporalAdjusters.previousOrSame(DayOfWeek.FRIDAY))); //2021-11-26
//获取下周二
System.out.println("下周二:"+now.plusWeeks(1).with(ChronoField.DAY_OF_WEEK, 2)); //2021-12-07
//(往后不包括当天)获取当前日期的下一个周日 如果今天是周日,则返回下周日的时间 如果今天是星期一,则返回本周日的时间
System.out.println("下一个周日(不包括当天):"+now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY))); //2021-12-05
//(往后包括当天)最近星期五的日期 如果今天是星期五,则返回今天日期
System.out.println("下一个周日(包括当天):"+now.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY))); //2021-12-03
四. 自定义TemporalAdjuster 实现
我们可以通过两种不同方式自定义TemporalAdjuster 实现。
请看如何通过Temporal.with()方法获得2021-12-02之后7天的日期:
LocalDate localDate = LocalDate.of(2021, 12, 2); TemporalAdjuster temporalAdjuster = t -> t.plus(Period.ofDays(7)); LocalDate result = localDate.with(temporalAdjuster); String fourteenDaysAfterDate = "2021-12-09"; System.out.println(fourteenDaysAfterDate.equals(result.toString()));//true
该示例中,使用了lambda表达式,设置temporalAdjuster为给localDate.of(2021, 12, 2)对象增加7天。
下面看如何获得2021-12-02之后的工作日,通过自定义TemporalAdjuster 实现,但这次使用static工厂方法ofDateAdjuster():
获取下一个工作日
LocalDate localDate = LocalDate.of(2021, 12, 2);
TemporalAdjuster NEXT_WORKING_DAY = TemporalAdjusters.ofDateAdjuster(date -> {
DayOfWeek dayOfWeek = date.getDayOfWeek();
if (dayOfWeek.equals(DayOfWeek.FRIDAY)) {
return localDate.plusDays(3);
} else if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {
return localDate.plusDays(2);
} else {
return localDate.plusDays(1);
}
});
System.out.println("下一个工作日:" + localDate.with(NEXT_WORKING_DAY));
简写为:
LocalDate nextWorkDay = LocalDate.now().with(tempDate -> {
LocalDate localDate = (LocalDate) tempDate;
DayOfWeek dayOfWeek = localDate.getDayOfWeek();
if (dayOfWeek.equals(DayOfWeek.FRIDAY)) {
return localDate.plusDays(3);
} else if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {
return localDate.plusDays(2);
} else {
return localDate.plusDays(1);
}
});
System.out.println("下一个工作日:" + nextWorkDay);
下面通过实现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);
}
}
测试代码如下:
LocalDate localDate = LocalDate.of(2021, 12, 3);
CustomTemporalAdjuster temporalAdjuster = new CustomTemporalAdjuster();
LocalDate nextWorkingDay = localDate.with(temporalAdjuster);
System.out.println("2021-12-06".equals(nextWorkingDay.toString())); //true