SimpleDateFormat 星期年

SimpleDateFormat week year

java8 GregorianCalendar DOC

周年与WEEK_OF_YEAR周期同步。第一周和最后一周(含)之间的所有周都具有相同的周年值。因此,一周的第一天和最后一天可能具有不同的日历年值。

例如,1998 年 1 月 1 日是星期四。如果 getFirstDayOfWeek() 为星期一且 getMinimalDaysInFirstWeek() 为 4(ISO 8601 标准兼容设置),则 1998 年的第 1 周从 1997 年 12 月 29 日开始,到 1998 年 1 月 4 日结束。最后三天的星期年份为 1998 年日历年 1997。但是,如果 getFirstDayOfWeek() 是 SUNDAY,则 1998 年的第 1 周从 1998 年 1 月 4 日开始,到 1998 年 1 月 10 日结束; 1998 年的前三天是 1997 年第 53 周的一部分,他们的星期年是 1997 年。

正如 DOC 所说,如果我将 FirstDayOfWeek 设置为 SUNDAY 并将 MinimalDaysInFirstWeek 设置为 4,那么 1998-01-01 的星期年份应该是 1997,但 junit 结果是 1998。

Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.YEAR, 1998);
    calendar.set(Calendar.MONTH, 0);
    calendar.set(Calendar.DAY_OF_MONTH, 1);
    calendar.setMinimalDaysInFirstWeek(4);
    calendar.setFirstDayOfWeek(Calendar.SUNDAY);

    System.out.println(calendar.getTimeZone());
    System.out.println(calendar.getMinimalDaysInFirstWeek());
    System.out.println(calendar.getFirstDayOfWeek());

    SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd");
    System.out.println(sdf.format(calendar.getTime()));

junit 结果是: sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=29,lastRule=null]

4

1

1998-01-01

TL;DR: 格式化程序使用自己的周编号

日期格式化程序使用自己的周编号方案,而不是日期的编号方案(在您的情况下是 Calendar 对象)。我正在演示如何使用 java.time 现代 Java 日期和时间 API。具体来说,我使用的是 LocalDateLocalDate 始终是 ISO 日历系统中的日期。

    LocalDate date = LocalDate.of(1998, Month.JANUARY, 1);
    DateTimeFormatter baseFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd");

    DateTimeFormatter chinaFormatter = baseFormatter.withLocale(Locale.CHINA);
    System.out.println("China:   " + date.format(chinaFormatter));

    DateTimeFormatter franceFormatter = baseFormatter.withLocale(Locale.FRANCE);
    System.out.println("France:  " + date.format(franceFormatter));

    DateTimeFormatter irelandFormatter = baseFormatter.withLocale(Locale.forLanguageTag("en-IE"));
    System.out.println("Ireland: " + date.format(irelandFormatter));

此片段的输出是:

China:   1998-01-01
France:  1998-01-01
Ireland: 1997-01-01
  • 如果您的默认语言环境是中国,则您的格式化程序使用的是中国周。它们从星期日开始,第 1 周是包含 1 月 1 日的那一周(例如在美国,作为另一个例子)。所以 1998 年 1 月 1 日必须属于 1998 年的星期。
  • 法国使用 ISO 编号:一周从星期一开始,正如您所说,在这种情况下,1998 年的第 1 周从 1997 年 12 月 29 日开始。所以我们又得到 1998。
  • 爱尔兰是少数几个使用您在问题中尝试获得的混合方案的国家之一:第一周的最少天数为 4(与 ISO 相同),星期日是一周的第一天(与 ISO 相同)在中国和美国)。因此,使用以爱尔兰作为区域设置国家/地区的格式化程序可为您提供您想要获得的结果,1997 年。

从您的日期中获取 1997 年的星期的另一种方法是将您自己的 WeekFields 对象放在一起。那你就不用担心语言环境了。

    WeekFields myWeekFields = WeekFields.of(DayOfWeek.SUNDAY, 4);
    int weekYear = date.get(myWeekFields.weekBasedYear());
    System.out.println("Week year: " + weekYear);

Week year: 1997

java.time??

您使用的 class 日期和时间 CalendarSimpleDateFormat 设计不佳且早已过时。

从您的文档 link 看来,您正在使用 Java 8,如果是这样,您绝对没有理由为旧的 class 挣扎。像我上面那样使用 java.time 。 Java 6 和 7 的反向移植也存在。

问题中的代码怎么没用?

您使用 calendar.getTime() 占用了 Calendar 的时间。这个 returns 一个 Date(另一个设计糟糕且过时的 class)。一个Date是一个时间点,仅此而已。它没有任何周数或周年的概念。您将此 Date 传递给了您的 SimpleDateFormat,它无法检测到 Date 最初来自具有第一周特定天数设置的 Calendar 对象,并且一周的第一天。相反,SimpleDateFormat 使用其自己的周定义。它总是那样做。由于您没有为 SimpleDateFormat 显式设置语言环境或日历,它使用了 JVM 的默认语言环境。这产生了 1998 年的一周,就像在绝大多数语言环境中一样。