基于周的模式无法按预期工作

Week-based pattern does not work as expected

我希望这两个格式化程序是等价的:

DateTimeFormatter fromBuilder = new DateTimeFormatterBuilder()
    .appendValue(IsoFields.WEEK_BASED_YEAR, 4)
    .appendLiteral('-')
    .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2)
    .toFormatter();
DateTimeFormatter fromPattern = DateTimeFormatter.ofPattern("YYYY-ww");

但他们给出的结果不一样:

LocalDate date = LocalDate.of(2017, 1, 1);
System.out.printf("from builder: %s%n", fromBuilder.format(date));  // prints 'from builder: 2016-52'
System.out.printf("from pattern: %s%n", fromPattern.format(date));  // prints 'from pattern: 2017-01'

我错过了什么?

Yw 模式 correspond to a localized version of week-fields,使用 JVM 的默认语言环境 (java.util.Locale)。第二个格式化程序相当于:

// localized week fields (using default Locale)
WeekFields weekFields = WeekFields.of(Locale.getDefault());
// equivalent to YYYY-ww
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    .appendValue(weekFields.weekBasedYear(), 4)
    .appendLiteral('-')
    .appendValue(weekFields.weekOfWeekBasedYear(), 2)
    .toFormatter();

由于这取决于语言环境,它可以或不能像 IsoFields 那样工作。根据 JVM 的默认语言环境,上面创建的 WeekFields 会有不同的行为。

另一方面,

IsoFields 遵循 ISO-8601 定义来定义基于周的字段,如 described in the javadoc:

The first week of a week-based-year is the first Monday-based week of the standard ISO year that has at least 4 days in the new year.

  • If January 1st is Monday then week 1 starts on January 1st
  • If January 1st is Tuesday then week 1 starts on December 31st of the previous standard year
  • If January 1st is Wednesday then week 1 starts on December 30th of the previous standard year
  • If January 1st is Thursday then week 1 starts on December 29th of the previous standard year
  • If January 1st is Friday then week 1 starts on January 4th
  • If January 1st is Saturday then week 1 starts on January 3rd
  • If January 1st is Sunday then week 1 starts on January 2nd

由于2017-01-01是星期天,所以它对应于上面的最后一行:第1周开始于1月2日nd 2017, 所以1月1日st 2017还在2016年的最后一周


您可以通过调用方法 getFirstDayOfWeek()getMinimalDaysInFirstWeek() 来检查您的 WeekFields 实例与 IsoFields 有何不同 - 它们用于 calculate the values of the respecitive week-based fields:

A week is defined by:

  • The first day-of-week. For example, the ISO-8601 standard considers Monday to be the first day-of-week.
  • The minimal number of days in the first week. For example, the ISO-8601 standard counts the first week as needing at least 4 days.

Together these two values allow a year or month to be divided into weeks.

在我使用的 JVM 中,默认语言环境是 pt_BR,并且创建的 WeekFields 将一周的第一天设置为星期日,将第一周的最少天数设置为 1。检查你的,你会发现它也不同于 IsoFields


您可以使用 constant WeekFields.ISO 检查 ISO 的定义:getFirstDayOfWeek() returns 星期一和 getMinimalDaysInFirstWeek() returns 4.


此外,请注意 IsoFieldsWeekFields.ISO 之间存在细微差别。引用 JodaStephen's comment in this thread:

The only observable difference was that WeekFields operates on all calendar systems (by converting to ISO) whereas IsoFields only operates on ISO (and rejects other calendar systems)