SimpleDateFormat 上周错误的一周

SimpleDateFormat wrong week of year for last week

我需要获取给定日期在一年中的第几周。使用 SimpleDateFormat 会在一年的最后一周产生错误的结果。

示例:

这会正确生成第 52 周:

SimpleDateFormat w = new SimpleDateFormat("w");
Calendar c = Calendar.getInstance();
c.set(2021, 11, 25);
System.out.println("Week: ${w.format(c.getTime())}");

产生:Week: 52

但是第二天已经被认为是明年的第一个星期了?

SimpleDateFormat w = new SimpleDateFormat("w");
Calendar c = Calendar.getInstance();
c.set(2021, 11, 26);
System.out.println("Week: ${w.format(c.getTime())}");

产生:Week: 1

这只发生在 Java 7 而不是 Java 8 及以上!

不要使用 Calendar。它已经过时了,更重要的是,非常糟糕 API.

关于我的腿有什么问题,有一个清单。与这里相关的大约 200 件事中的具体一件是,愚蠢地,它的月份值是 0 索引。那么,“12、3”?那是十一月 3 日,或者任何你想称呼的 第 13 个月。那,或者日历不做第 13 个月,在这种情况下,它会宽大地假设您打算说 2022 年 1 月 3 日。不管怎样,那是第 1 周。

那么为什么 11 月 2 日(或者如果您愿意,通过翻转,2022 年 1 月 2 日)是“第 52 周”?

Because it is.

周编号很奇怪,但它们必须如此。一周从星期一开始(或星期日,以我愚蠢的标准爱美国弟兄们),并且不能从任何其他日子开始。这意味着除非 1 月 1 日恰好是星期一,否则就会出现奇怪的情况; 2021 年的天数计为 'week 1 of 2022',或 2022 年的天数计为 'week 52 of 2021'。事实上,有时必须有一个星期 53。毕竟,52*7 是 364,但一年有 365.2475 天,所以除非你只是想让某些日子不存在,否则每个通常需要 53 周才能全部加起来。

改用java.time

LocalDate ld = LocalDate.of(2021, 12, 3);
WeekFields wf = WeekFields.of(Locale.ENGLISH);
int weekNumber = ld.get(wf.weekOfWeekBasedYear());

java.time 做很多事情都很棒,其中一件事情做得很好就是它不会隐藏复杂的事情。例如,'when does a week start' 是 不可回答的 ,除非你告诉我你在这个星球上的什么地方问这个问题。因此,'which week is it' 实际上不是一个可以回答的问题,除非您确切地告诉我我们使用的是哪种周计数系统,并且没有足够普遍接受的标准。因此,您 必须 通过制作单独的 WeekFields 实例的繁琐程序来捕获该信息。我们在这里根据语言环境来做。

实际上这并不特定于 Calendar,因为如果 运行 在 12 月 29 日,这也会显示第 1 周:例如:

System.out.println("Week: ${new SimpleDateFormat("w").format(new Date())}");

但它是Java 7所特有的。它在Java 8.

中已修复

我在这里找到了解释(正如@rzwitserloot 也解释的那样):

https://docs.oracle.com/javase/8/docs/api/java/util/GregorianCalendar.html

A week year is in sync with a WEEK_OF_YEAR cycle. All weeks between the first and last weeks (inclusive) have the same week year value. Therefore, the first and last days of a week year may have different calendar year values.

For example, January 1, 1998 is a Thursday. If getFirstDayOfWeek() is MONDAY and getMinimalDaysInFirstWeek() is 4 (ISO 8601 standard compatible setting), then week 1 of 1998 starts on December 29, 1997, and ends on January 4, 1998. The week year is 1998 for the last three days of calendar year 1997. If, however, getFirstDayOfWeek() is SUNDAY, then week 1 of 1998 starts on January 4, 1998, and ends on January 10, 1998; the first three days of 1998 then are part of week 53 of 1997 and their week year is 1997.

这真的很有趣..