java 8 的 `java.time` api 中,获取指定日期的 `weekfields` 最直接的方式是调用静态工厂方法 `weekfields.of(locale locale)`。你需要先确定业务逻辑所遵循的区域设置(例如中国使用 `locale.china`),然后传入该方法即可得到一个包含星期起始日和每周最小天数信息的 `weekfields` 实例。拿到这个实例后,就可以配合 `localdate` 的 `get(weekfields.weekofweekbasedyear())` 等方法来提取周数或星期几。

如何根据 Locale 获取 WeekFields 实例
要获取符合特定地区习惯的周定义,只需调用 `WeekFields.of()` 并传入对应的 `Locale` 对象。不同的国家对于一周从星期几开始、以及最少需要几天才算完整的一周有不同的规定。例如,在中国,通常认为周一是一周的开始;而在美国,周日往往被视为一周的开始。通过这种方式获得的 `WeekFields` 对象封装了这些规则,后续可以直接用于日期字段的解析和格式化。

import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.Locale;
public class WeekFieldDemo {
public static void main(String[] args) {
// 1. 获取基于中国区域的 WeekFields
WeekFields weekFieldsCN = WeekFields.of(Locale.CHINA);
// 2. 获取基于美国区域的 WeekFields
WeekFields weekFieldsUS = WeekFields.of(Locale.US);
// 3. 验证第一天的区别
System.out.println("China first day: " + weekFieldsCN.getFirstDayOfWeek());
System.out.println("US first day: " + weekFieldsUS.getFirstDayOfWeek());
// 4. 获取最小天数
System.out.println("China min days: " + weekFieldsCN.getMinimalDaysInFirstWeek());
System.out.println("US min days: " + weekFieldsUS.getMinimalDaysInFirstWeek());
}
}运行上述代码,控制台会输出:China first day: MONDAY, US first day: SUNDAY, China min days: 1, US min days: 1。这表明 `WeekFields.of(Locale)` 能够准确区分不同地区的周起始习惯。开发者在项目中应统一使用一个固定的 Locale 来获取 `WeekFields`,以避免因区域切换导致的周数计算偏差。
立即学习“Java免费学习笔记(深入)”;
如何使用 WeekFields 提取日期中的周信息
获取到 `WeekFields` 实例后,下一步通常是利用它从 `LocalDate` 中提取具体的周数或星期几。`LocalDate` 提供了 `get(TemporalField field)` 方法,接受一个 `TemporalField` 作为参数。`WeekFields` 提供了几个关键的字段常量,如 `weekOfWeekBasedYear()` 和 `dayOfWeek()`。注意区分 `dayOfWeek()` 返回的是标准的 ISO-8601 星期几(1=Monday, 7=Sunday),而 `weekOfYear()` 返回的是基于该 `WeekFields` 定义的年份中的第几周。

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.Locale;
public class ExtractWeekInfo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2023, 1, 1); // 2023-01-01 is a Sunday
WeekFields wf = WeekFields.of(Locale.CHINA);
// 获取基于当前 WeekFields 的星期几 (1=Mon, ..., 7=Sun)
int dayOfWeek = date.get(wf.dayOfWeek());
// 获取基于当前 WeekFields 的周数
int weekOfYear = date.get(wf.weekOfWeekBasedYear());
// 获取基于当前 WeekFields 的周基年
int weekBasedYear = date.get(wf.weekBasedYear());
System.out.println("Date: " + date);
System.out.println("Day of Week: " + dayOfWeek + " (" + DayOfWeek.of(dayOfWeek) + ")");
System.out.println("Week of Year: " + weekOfYear);
System.out.println("Week Based Year: " + weekBasedYear);
}
}以 2023 年 1 月 1 日(周日)为例,在中国区域设置下,由于周一才是一周的开始,且该天属于上一年的最后一周,因此 `weekOfWeekBasedYear()` 可能会返回上一年的周数,而 `weekBasedYear()` 也会相应调整。这体现了 `WeekFields` 在处理跨年周数时的严谨性。开发者在使用时,务必确认是否需要“周基年”(Week-Based-Year),因为 ISO-8601 标准下的年份和自然年并不总是完全对应。
当日期处于年初或年末时 WeekFields 的行为
在年初或年末,`WeekFields` 的计算逻辑尤为关键,因为此时涉及“周基年”的概念。如果某年的最后一天是周四之前的某一天,或者某年的第一天是周五之后的某一天,那么这一天可能不属于该自然年,而是属于相邻年份的“周基年”。`WeekFields` 通过 `minimalDaysInFirstWeek`(第一周的最小天数)来决定这一点。如果第一周的天数少于这个阈值,则该周被归入上一年。
import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.Locale;
public class EdgeCaseTest {
public static void main(String[] args) {
// 测试 2024-12-31 (Tuesday)
LocalDate end2024 = LocalDate.of(2024, 12, 31);
WeekFields wf = WeekFields.of(Locale.CHINA);
System.out.println("Date: " + end2024);
System.out.println("Week: " + end2024.get(wf.weekOfWeekBasedYear()));
System.out.println("Year: " + end2024.get(wf.weekBasedYear()));
// 测试 2025-01-01 (Wednesday)
LocalDate start2025 = LocalDate.of(2025, 1, 1);
System.out.println("\nDate: " + start2025);
System.out.println("Week: " + start2025.get(wf.weekOfWeekBasedYear()));
System.out.println("Year: " + start2025.get(wf.weekBasedYear()));
}
}在上述代码中,2024 年 12 月 31 日是周二。在中国规则下(周一开始,至少1天),这一周仍然属于 2024 年的第 53 周(假设)。而 2025 年 1 月 1 日是周三,它属于 2025 年的第 1 周。但如果我们将日期改为 2025 年 1 月 5 日(周日),在某些严格的 ISO 定义下,它可能仍被视为 2024 年的最后一周。通过实际运行代码,可以观察到 `weekBasedYear` 与 `year` 字段是否一致,从而判断当前日期是否发生了年份归属的偏移。这种边界情况的处理是企业级日历应用开发中的常见需求。


















