你在比较苹果和香蕉。
格式模式字母w 为您提供week-of-week-based-year。在所有日历系统中,我知道它在 1 到 53 的范围内。它使用格式化程序区域设置的周编号方案。在您的情况下,这是 JVM 的默认语言环境,因为您没有明确设置语言环境。在许多(几乎所有?)周编号系统中,第 1 周有时可能会在新年之前开始。在这种情况下,第 1 周对于 12 月 31 日是正确的。
weekOfYear() 为您提供一年中的第几周,从 0 到 54。它与新年前后(并且仅在那时)基于每周的一周不同。与基于周数的年份相反,周数总是为您提供与日历年相关的周数,在您的示例中为 2000 年,因此对于 12 月 31 日,这永远不会是 1。
如何从格式化程序中获取您的期望值
格式化程序也可以使用来自WeekFields 对象的weekOfYear(),以便获得一致的结果。例如:
LocalDate date = LocalDate.of(2000, Month.DECEMBER, 31);
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendValue(WeekFields.ISO.weekOfYear())
.toFormatter();
System.out.println("Iso week # from formatter: " + date.format(formatter));
输出:
来自格式化程序的 ISO 周#:52
Java 不正确吗?
在www.timeanddate.com 上,我构造了this 2000 calendar for the United States。在更多选项 -> 高级自定义 -> 周下,我选择了“是 - 1 月 1 日始终在第 1 周”,以适合美国。正如您在链接中看到的,12 月 31 日现在是第 1 周。
您是正确的,在 ISO 中,2000 年 12 月 31 日在第 52 周。在 ISO 中,其他年份的 12 月 31 日也可能在下一年的第 1 周。
用 Java 模拟 IBM 的 WEEKNUM 函数
编辑:很明显,IBM 和 Java 对周数的定义并不完全一致。与其讨论谁对谁错,我更愿意用 Java 模拟 IBM 的方式,因为我知道这是你真正需要的。
凭经验
因此,IBM 既不遵循 Java 所称的一年中的周,也不遵循 Java 所称的基于周的周。让我们在您的链接中的示例日期中查看 Java 的意见:
LocalDate[] sampleDates = {
LocalDate.of(2000, Month.JANUARY, 1),
LocalDate.of(2000, Month.JANUARY, 2),
LocalDate.of(2000, Month.JANUARY, 3),
LocalDate.of(2000, Month.DECEMBER, 31),
LocalDate.of(2014, Month.JANUARY, 2),
LocalDate.of(2014, Month.JUNE, 9),
LocalDate.of(2014, Month.DECEMBER, 31) };
System.out.println(" US US ISO ISO");
System.out.println("Input date week based of year week based of year");
for (LocalDate date : sampleDates) {
System.out.format("%s %02d %02d %02d %02d%n", date,
date.get(WeekFields.SUNDAY_START.weekOfWeekBasedYear()),
date.get(WeekFields.SUNDAY_START.weekOfYear()),
date.get(WeekFields.ISO.weekOfWeekBasedYear()),
date.get(WeekFields.ISO.weekOfYear()));
}
输出:
US US ISO ISO
Input date week based of year week based of year
2000-01-01 01 01 52 00
2000-01-02 02 02 52 00
2000-01-03 02 02 01 01
2000-12-31 01 54 52 52
2014-01-02 01 01 01 01
2014-06-09 24 24 24 24
2014-12-31 01 53 01 53
与您的表格相比,对于美国来说,IBM 似乎正在生产 Java 所称的“一年中的一周”。对于 ISO,IBM 生成 Java 所称的基于周的年。
文档
我相信我找到了与您的一致的 IBM WEEKNUM 函数描述。它去:
- WEEKNUM 函数将给定的儒略/公历日期转换为周数。此功能有 2 个版本,美国标准
格式和 ISO 格式。
- WEEKNUM=USA 函数返回一个 1 到 54 范围内的整数,表示一年中的第几周。一周从星期日开始,并且
1 月 1 日始终是第一周。
- WEEKNUM=ISO 函数返回一个 1 到 53 范围内的整数,表示一年中的第几周。一周从星期一开始,然后
包括7天。第 1 周是一年中包含
星期四,相当于包含 1 月 4 日的第一周。
虽然这不是非常精确,但它与我之前的解释一致。基于周数的年份在任何地方都不会上升到 54,因此要在美国发生这种情况,我们需要对周数进行解释,其中周数可能会在新年从 54 变为 1。相反,如果第 1 周的开始时间晚于 1 月 1 日,则 ISO 一年中的周数可能为 0,但 IBM 不允许为 0,因此这里他们可能使用基于周数的年份。
用 Java 模拟所有这些还不错:
public static enum IBM_WEEKNUM_VERSION { USA, ISO };
public static int ibmWeeknum(IBM_WEEKNUM_VERSION version, LocalDate date) {
switch (version) {
case USA:
return date.get(WeekFields.SUNDAY_START.weekOfYear());
case ISO:
return date.get(WeekFields.ISO.weekOfWeekBasedYear());
default:
throw new IllegalArgumentException(String.valueOf(version));
}
}
在相同的采样日期试用:
for (LocalDate date : sampleDates) {
System.out.format("%s %02d %02d%n", date,
ibmWeeknum(IBM_WEEKNUM_VERSION.USA, date),
ibmWeeknum(IBM_WEEKNUM_VERSION.ISO, date));
}
2000-01-01 01 52
2000-01-02 02 52
2000-01-03 02 01
2000-12-31 54 52
2014-01-02 01 01
2014-06-09 24 24
2014-12-31 53 01
一方面,它与您的示例 100% 一致。另一方面,我们无法 100% 确定 IBM 功能的工作情况。例如,我建议您在 20 年期间每年的第一周和最后两周的日期测试该方法。
链接