外国的文化习惯和外国的代码设计其实还是有很大差别的,毕竟代码是全球的人都要用的,是不能强行说偏袒某一方的(不像现在的漂亮国,扯远了),只能说代码里唯一借鉴了外国的只是用字母而已,其实代码设计是一个逻辑思考过程,题主太焦急了一点,不妨,我们慢慢来看
首先是TemporalAdjusters.previous
方法,在该方法的注释中已经提到了,该方法采用的时间字段是ChronoField.DAY_OF_WEEK
,也就是按照一周7天来算,也就是满打满算的一周七天,并且返回上一次出现的你传入的DayOfWeek
注意这里说的是上一次的,而不是上一周的
有区别么?当然有,举个例子,还是用你的LocaDate.of(2020,10,21)
,虽然
TemporalAdjusters.previous(DayOfWeek.SUNDAY)
最终返回的是2020-10-18
,那如果填入的是DayOfWeek.MONDAY
,也就是上一个周一,会是多少呢?难道会是2020-10-12
日么?也就是上一周周一。不是的,答案其实是2020-10-19
,也就是上一个周一,不是上一周的周一
所以首先在方法选型上,可能就不太对口,更不用谈是不是周一开始一周还是周日开始一周了,用这个方法是完成不了根据一个时间取到上一周的某个星期的问题
(如果不想看下面的思路,可能写的有点绕,容易混乱,可以直接拖到最下面查看最终代码)
当然也不是说TemporalAdjusters.previous
方法完全没用,起码在注释中已经说到,这样的处理适用于很多日历系统,算是比较通用的方法吧
不说TemporalAdjusters.previous
了,咱们来看看题主要解决的问题如何操作。
我觉得关键就是在于上一个和上一周的区别
- 上一个:只是说往前遍历,找到第一次出现
- 上一周:应该首先给予一个周定义,它应该定义在更大范围内,比如月份里的第几周,这个周定义是相对于
DayOfWeek
的,比DayOfWeek
更大范围,在更大范围的定位里,找到上一周,然后再回到上一周中,根据DayOfWeek
定义里需要修改的数值进行修改。当然你也可以先修改DayOfWeek
定义里需要的数值,然后再找到上一周。顺序肯定是可以颠倒的
所以说从理解上来说是有2步要做的。如果是对Java8时间API设计比较了解的话,应该知道,在API
设计中描述飘渺的时间,主要就是靠定义,也就是时间字段的定义,一个时间,用不同的时间字段去描述,是可以获取到不同的值,这也就是时间字段+数值=时间
在时间顶层接口TemporalAccessor
的get
方法就可以见一斑
那时间字段TemporalField
由于它是定义,所以时间定义上肯定会有单位,也就是TemporalUnit
,以及范围,比如一个分钟有60秒,一周有7天,一年有365天等等,这都是基于某个单位下的数值范围。
所以我们现在需要的就是构造一个周定义,单位肯定是天,范围也是7天,但是最小一周也有1天,不像之前提到的的ChronoField.DAY_OF_WEEK
,它的最小一周也有7天,因为是满打满算嘛
那这个定义我在另一个回答里有提到就是参考WeekFields
的静态变量SUNDAY_START
WeekFields
可以简单理解为构建自定义一周的工具类,里面有个静态变量SUNDAY_START
就是以周日为起点,最小一周只有1天的WeekFields
定义了
此时还不是周定义,因为周定义需要在月份中,而恰好WeekFields
提供了方法weekOfMonth
TemporalField weekOfMonthTemporalField = WeekFields.SUNDAY_START.weekOfMonth();
weekOfMonthTemporalField
才是我们要找的,以周日为一周起点的更大范围下的周定义
有了它,我们就可以构造一个TemporalAdjuster
了,用于把参数日期按照weekOfMonthTemporalField
的定义调整到上一周
TemporalAdjuster temporalAdjuster = temporal -> temporal.minus(1, weekOfMonthTemporalField.getBaseUnit());
我们这里采用了Temporal
的minus
方法,减去一个1个weekOfMonthTemporalField
定义下的单位,因为之前我们提到了TemporalField
本来就是由TemporalUnit
组成的,所以这样操作是合理的
当然由于这里是时间单位,不是时间字段,所以不论是周一开始的周,还是周日开始的周,它们的单位都是周,而周在Java8的API中是有枚举的,也就是ChronoUnit
其中的WEEKS
,所以我们也可以这么写
TemporalAdjuster temporalAdjuster = temporal -> temporal.minus(1, ChronoUnit.WEEKS);
其实就是日期减了一周,然后减了一周之后,我们在按照要求把时间调整(with
方法,带TemporalField
参数的)到传入的DayOfWeek
即可,调整需要涉及时间字段,那我们就从刚才的周日开始的WeekFields
定义取出DayOfWeek
的定义,也就是
TemporalField dayOfWeekTemporalField = WeekFields.SUNDAY_START.dayOfWeek()
那这样,我们的TemporalAdjuster
就变为
TemporalAdjuster temporalAdjuster = temporal -> temporal.minus(1, ChronoUnit.WEEKS)
.with(dayOfWeekTemporalField, 1);
为啥填入的是1,因为dayOfWeekTemporalField
是时间字段,是定义,在这个定义下,周日是第一天,所以这个with
方法含义就是按照dayOfWeekTemporalField
的定义修改该字段值为1
整合一下完整的代码:
LocalDate date = LocalDate.of(2020,10,21);
TemporalField dayOfWeekTemporalField = WeekFields.SUNDAY_START.dayOfWeek();
TemporalAdjuster temporalAdjuster = temporal -> temporal.minus(1, WEEKS)
.with(dayOfWeekTemporalField, 1);
LocalDate newLocalDate = date.with(temporalAdjuster);
System.out.println(newLocalDate);
你也可以自己模仿TemporalAdjusters
创建一个属于自己的TemporalAdjuster
工厂CustomTemporalAdjusters
public class CustomTemporalAdjusters {
public static TemporalAdjuster sundayOfPreviousWeek() {
return temporal -> temporal.minus(1, WEEKS)
.with(WeekFields.SUNDAY_START.dayOfWeek(), 1);
}
}
然后调用起来就比较方便了
LocalDate date = LocalDate.of(2020,10,21);
LocalDate newLocalDate = date.with(CustomTemporalAdjusters.sundayOfPreviousWeek());
System.out.println(newLocalDate);
但是这样做CustomTemporalAdjusters
中的处理还是有点局限性,万一想看上一周的周三,周四呢?现在只能处理周日,所以我们再稍微改一下就可以了,主要修改最后的调整方法,也就是with(WeekFields.SUNDAY_START.dayOfWeek(), 1);
,这里为什么是1,是因为在WeekFields.SUNDAY_START.dayOfWeek()
的定义下是1,也就是DayOfWeek.SUNDAY
在WeekFields.SUNDAY_START.dayOfWeek()
定义为1,所以我们只要把需要查看的DayOfWeek
放到WeekFields.SUNDAY_START.dayOfWeek()
的定义里获取值即可,这个值就是需要修改的。也就是用到我们TemporalAccessor
的get
方法
最终代码应该是这样的
public class CustomTemporalAdjusters {
public static TemporalAdjuster sundayOfPreviousWeek() {
return dayOfPreviousWeek(DayOfWeek.SUNDAY);
}
public static TemporalAdjuster dayOfPreviousWeek(DayOfWeek dayOfWeek) {
TemporalField temporalField = WeekFields.SUNDAY_START.dayOfWeek();
return temporal -> temporal.minus(1, WEEKS)
.with(temporalField, dayOfWeek.get(temporalField));
}
}
调用的时候,两种方法都可以
LocalDate date = LocalDate.of(2020,10,21);
date.with(CustomTemporalAdjusters.dayOfPreviousWeek(DayOfWeek.SUNDAY));
date.with(CustomTemporalAdjusters.sundayOfPreviousWeek());
以上就是我的思路和答案,希望能对你有所帮助,拜了个拜(′▽`〃)