SimpleDateFormat 星期年
SimpleDateFormat week year
周年与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。具体来说,我使用的是 LocalDate
。 LocalDate
始终是 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 日期和时间 Calendar
和 SimpleDateFormat
设计不佳且早已过时。
从您的文档 link 看来,您正在使用 Java 8,如果是这样,您绝对没有理由为旧的 class 挣扎。像我上面那样使用 java.time 。 Java 6 和 7 的反向移植也存在。
问题中的代码怎么没用?
您使用 calendar.getTime()
占用了 Calendar
的时间。这个 returns 一个 Date
(另一个设计糟糕且过时的 class)。一个Date
是一个时间点,仅此而已。它没有任何周数或周年的概念。您将此 Date
传递给了您的 SimpleDateFormat
,它无法检测到 Date
最初来自具有第一周特定天数设置的 Calendar
对象,并且一周的第一天。相反,SimpleDateFormat
使用其自己的周定义。它总是那样做。由于您没有为 SimpleDateFormat
显式设置语言环境或日历,它使用了 JVM 的默认语言环境。这产生了 1998 年的一周,就像在绝大多数语言环境中一样。
周年与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。具体来说,我使用的是 LocalDate
。 LocalDate
始终是 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 日期和时间 Calendar
和 SimpleDateFormat
设计不佳且早已过时。
从您的文档 link 看来,您正在使用 Java 8,如果是这样,您绝对没有理由为旧的 class 挣扎。像我上面那样使用 java.time 。 Java 6 和 7 的反向移植也存在。
问题中的代码怎么没用?
您使用 calendar.getTime()
占用了 Calendar
的时间。这个 returns 一个 Date
(另一个设计糟糕且过时的 class)。一个Date
是一个时间点,仅此而已。它没有任何周数或周年的概念。您将此 Date
传递给了您的 SimpleDateFormat
,它无法检测到 Date
最初来自具有第一周特定天数设置的 Calendar
对象,并且一周的第一天。相反,SimpleDateFormat
使用其自己的周定义。它总是那样做。由于您没有为 SimpleDateFormat
显式设置语言环境或日历,它使用了 JVM 的默认语言环境。这产生了 1998 年的一周,就像在绝大多数语言环境中一样。