上周的默认年份数 Java 不正确
Last week number of year in default Java is not correct
代码示例:
LocalDate date = LocalDate.of(2000, 12, 31);
System.out.println("Default Java week #" + date.format(DateTimeFormatter.ofPattern("ww")));
System.out.println("Iso week #" + date.get(WeekFields.ISO.weekOfYear()));
System.out.println("Usa week #" + date.get(WeekFields.SUNDAY_START.weekOfYear()));
---------------------
Default Java week #01
Iso week #52
Usa week #54
---------------------
ISO 8601 对第 01 周的定义是公历年(即一月)的第一个星期四。以下基于本周属性的定义是相互等价的,因为 ISO 周从星期一开始: 这是第一周,其大部分天数(4 天或更多)在一月。
美国格式:计算方法-第一周为1月1日,下周从下周日开始。
2000 年 12 月 31 日 - 星期日。参考周的标准,12 月 31 日(星期日)是任何标准(54 或 52)中最后一年的周。为什么Java说是01周?
P.S。 Locale.getDefault() --> en_US
你在比较苹果和香蕉。
格式模式字母 w
为您提供 基于周的年份。在所有日历系统中,我知道这是在 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 week # from formatter: 52
Java不正确吗?
在 www.timeanddate.com I constructed this 2000 calendar for the United States。在“更多选项”->“高级定制”->“周数”下,我选择适合美国的“是 - 1 月 1 日始终在第 1 周”。正如您在 link 中看到的那样,12 月 31 日现在是第 1 周。
在 ISO 中,2000 年 12 月 31 日在第 52 周是正确的。在 ISO 中,其他年份的 12 月 31 日也可能在次年的第 1 周。
在Java
中模拟IBM的WEEKNUM函数
编辑:很明显,IBM 和 Java 并不完全同意周数的定义。与其讨论谁对谁错,我更想在 Java 中模拟 IBM 的方式,因为我知道这才是你真正需要的。
根据经验
IBM 因此既不遵循 Java 所谓的一年中的一周,也不遵循 Java 所谓的一年中的一周。让我们看看 Java 在您的 link:
样本日期中的意见
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
与您的 table 相比,美国 IBM 似乎正在生产 Java 所谓的一年中的一周。对于 ISO,IBM 生成了 Java 所谓的基于周的年份。
文档
我相信我找到了与您一致的 IBM 的 WEEKNUM 函数的描述。它是:
- WEEKNUM function converts a given Julian/Gregorian date to number of week. There are 2 versions of this function, the standard USA
format and the ISO format.
- WEEKNUM=USA function returns an integer in the range of 1 to 54 that represents the week of the year. The week starts with Sunday, and
January 1 is always in the first week.
- WEEKNUM=ISO function returns an integer in the range of 1 to 53 that represents the week of the year. The week starts with Monday and
includes 7 days. Week 1 is the first week of the year to contain a
Thursday, which is equivalent to the first week containing January 4.
虽然这不是非常精确,但它与我之前的解释一致。基于年的周数没有任何地方可以达到 54,因此要在美国发生这种情况,我们需要年中的周解释,其中周数可能会在新年从 54 变为 1。相反,如果第 1 周开始时间晚于 1 月 1 日,ISO week-of-year 可能为 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 年的每一年的第一周和最后两周的日期测试该方法。
链接
- Scrrenshot of examples your required results, from IBM docs
- Date functions 来自 IBM z/OS 2.3.0 文档
代码示例:
LocalDate date = LocalDate.of(2000, 12, 31);
System.out.println("Default Java week #" + date.format(DateTimeFormatter.ofPattern("ww")));
System.out.println("Iso week #" + date.get(WeekFields.ISO.weekOfYear()));
System.out.println("Usa week #" + date.get(WeekFields.SUNDAY_START.weekOfYear()));
---------------------
Default Java week #01
Iso week #52
Usa week #54
---------------------
ISO 8601 对第 01 周的定义是公历年(即一月)的第一个星期四。以下基于本周属性的定义是相互等价的,因为 ISO 周从星期一开始: 这是第一周,其大部分天数(4 天或更多)在一月。
美国格式:计算方法-第一周为1月1日,下周从下周日开始。
2000 年 12 月 31 日 - 星期日。参考周的标准,12 月 31 日(星期日)是任何标准(54 或 52)中最后一年的周。为什么Java说是01周?
P.S。 Locale.getDefault() --> en_US
你在比较苹果和香蕉。
格式模式字母 w
为您提供 基于周的年份。在所有日历系统中,我知道这是在 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 week # from formatter: 52
Java不正确吗?
在 www.timeanddate.com I constructed this 2000 calendar for the United States。在“更多选项”->“高级定制”->“周数”下,我选择适合美国的“是 - 1 月 1 日始终在第 1 周”。正如您在 link 中看到的那样,12 月 31 日现在是第 1 周。
在 ISO 中,2000 年 12 月 31 日在第 52 周是正确的。在 ISO 中,其他年份的 12 月 31 日也可能在次年的第 1 周。
在Java
中模拟IBM的WEEKNUM函数编辑:很明显,IBM 和 Java 并不完全同意周数的定义。与其讨论谁对谁错,我更想在 Java 中模拟 IBM 的方式,因为我知道这才是你真正需要的。
根据经验
IBM 因此既不遵循 Java 所谓的一年中的一周,也不遵循 Java 所谓的一年中的一周。让我们看看 Java 在您的 link:
样本日期中的意见 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
与您的 table 相比,美国 IBM 似乎正在生产 Java 所谓的一年中的一周。对于 ISO,IBM 生成了 Java 所谓的基于周的年份。
文档
我相信我找到了与您一致的 IBM 的 WEEKNUM 函数的描述。它是:
- WEEKNUM function converts a given Julian/Gregorian date to number of week. There are 2 versions of this function, the standard USA format and the ISO format.
- WEEKNUM=USA function returns an integer in the range of 1 to 54 that represents the week of the year. The week starts with Sunday, and January 1 is always in the first week.
- WEEKNUM=ISO function returns an integer in the range of 1 to 53 that represents the week of the year. The week starts with Monday and includes 7 days. Week 1 is the first week of the year to contain a Thursday, which is equivalent to the first week containing January 4.
虽然这不是非常精确,但它与我之前的解释一致。基于年的周数没有任何地方可以达到 54,因此要在美国发生这种情况,我们需要年中的周解释,其中周数可能会在新年从 54 变为 1。相反,如果第 1 周开始时间晚于 1 月 1 日,ISO week-of-year 可能为 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 年的每一年的第一周和最后两周的日期测试该方法。
链接
- Scrrenshot of examples your required results, from IBM docs
- Date functions 来自 IBM z/OS 2.3.0 文档