这其实是计算一年中的周数(某日属于一年中的第几周)的两种算法。
简单来说,前者保证了1周不会跨越自然年的边界;后者保证了1周一定有7天,一定从某个DayOfWeek(如周一)开始,并且1周只属于某一年。
首先定义周
java.time.temporal.WeekFields
由WeekFields的静态工厂方法
WeekFields.of(DayOfWeek firstDayOfWeek, int minimalDaysInFirstWeek)
可以看出WeekFields由两个参数定义:firstDayOfWeek、minimalDaysInFirstWeek
firstDayOfWeek
:周几作为一周的第1天,ISO-8601定义周一是一周的第1天,周日作为一周的第1天也是一种很常用的定义。
minimalDaysInFirstWeek
:第1周至少几天,这个参数和接下来要介绍的算法相关,不理解不要紧,看到后面就明白了,ISO-8601定义第1周至少需要4天。
WeekFields类中还提供了常量,定义了ISO标准的周:
public static final WeekFields ISO = new WeekFields.of(DayOfWeek.MONDAY, 4);
下面的算法就以ISO定义的周为例进行讲解。
// 获取某一日的weekOfYear
LocalDate.of(2023, 1, 1).get(WeekFields.ISO.weekOfYear());
// 获取某一日的weekOfWeekBasedYear
LocalDate.of(2023, 1, 1).get(WeekFields.ISO.weekOfWeekBasedYear());
weekOfYear
该算法保证了一周不会跨越自然年的边界。
也就是说,一周一般还是从周一到周日,但是遇到12月31日会被截断,也就是一年的最后一周的最后一天一定是12月31日,下一年的第1周的第1天一定是1月1日。
并且,如果1月1日到当年的第1个周日如果小于4天(这个4天就是上面的minimalDaysInFirstWeek
),则记为第0周;如果大于4天,则记为第1周。
例如:
2023年1月1日是周日,1月1日到周日有1天 < 4天,所以1月1日是第0周,第0周就只有1月1日这1天;
第1周从1月2日开始;
2022年12月26日-31日这6天则属于2022年的第52周。
2015年1月1日是周四,到周日有4天,则1月1日-4日属于第1周,没有第0周;
第2周从1月5日开始
2018年1月1日是周一,则1月1日-7日属于第1周,没有第0周;第2周从1月7日开始。
weekOfWeekBasedYear
保证了1周一定有7天,一定从周一开始,并且1周只属于某一年。
一周从周一开始,到周日结束,没有例外,周数上也不会出现第0周。
如果一周不会被自然年截断,一年中的最后一周就很可能会跨年,这就产生了一个新的问题,这周究竟属于哪一年。如果一周有4天(minimalDaysInFirstWeek
)属于当年,则该周属于当年,否则该周属于上一年。
例子:
2023年1月1日属于2022年的第52周,第1周从1月2号开始
2014年12月29日-31日属于2015年的第1周