文章目录
前言
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