Подтвердить что ты не робот

Какова мотивация двух разных недельных определений в JSR-310?

Это два поля в пакете java.time.temporal:

IsoFields.WEEK_BASED_YEAR

WeekFields.ISO.weekBasedYear()

ISO-8601 определяет так называемую недельную дату, кроме двух других видов даты, а именно обычную календарную дату (состоящую из года, месяца и дня месяца) и порядковой даты (состоящей из года и дня, от года). Учет недели определяется в формате YYYY -WWww-e. w обозначает неделю недели, e для числового ISO-дня недели. Y означает недельный год и идентичен календарному году с исключением в начале или конце календарного года, поскольку недельный год привязан к недельному циклу, который может начаться в предыдущем году. Для понимания того, как формируется дата недели, важно два правила:

  • Недели всегда начинаются в понедельник.
  • Первая неделя календарного года - это неделя, которая содержит не менее четырех дней.

На первый взгляд оба поля JSR-310 выглядят одинаково, потому что ISO-8601 упоминает только один тип недели за год. Но подождите, удивите. Рассмотрим следующий пример кода:

LocalDate date1 = 
  LocalDate.of(2000, 2, 29).with(IsoFields.WEEK_BASED_YEAR, 2014);
System.out.println("IsoFields-Test: " + date1); // output: 2014-03-01

LocalDate date2 = 
  LocalDate.of(2000, 2, 29).with(WeekFields.ISO.weekBasedYear(), 2014);
System.out.println("WeekFields-Test: " + date2); // output: 2014-02-25

В то время как я очень хорошо понимаю вторую вариацию, я очень удивлен, увидев другой результат для первой даты, который использует "официальную" ISO-8601-ссылку в своем имени класса. Чтобы объяснить вычисленные результаты:

Дата 2000-02-29 соответствует 2000-W09-2 в ISO-weekdate-нотации, в то время как 2014-02-25 соответствует 2014-W09-2 , сохраняя неделю недели и день- из-недели. Пока что так хорошо. Эти сохраняющие характеристики для небольших полей аналогичны правилам изменения календарного года (который в большинстве случаев должен сохранять месяц и день месяца в календарной дате без изменений).

Но что относительно результата 2014-03-01? Здесь алгоритм просто добавил четыре дня к соответствующей дате недели, чтобы учесть разницу в поле "день месяца" (29 против 25). Я не нашел никакой исходной или официальной документации для этого поведения. Кто-нибудь знает, где мы можем найти оправдание разницы между этими двумя полями? Доступна ли какая-либо документация об алгоритмическом поведении?

UPDATE:

Теперь я попытался проверить самосогласованность нового API с этим выражением, чтобы узнать, какое из двух полей лучше поддерживать:

System.out.println(
  "14 week-based-years later = "
  + LocalDate.of(2000, 2, 29).plus(14, IsoFields.WEEK_BASED_YEARS));

Вывод 2014-03-01 аналогичен описанному случаю IsoFields.WEEK_BASED_YEAR, хотя я все еще считаю результат 2014-02-25 (= 2014-W09-2) более логичным. Так как эта временная единица также найдена в классе IsoFields, пока поведение самосогласовано внутри класса IsoFields. Похож на недокументированную и неинтуитивную "функцию".

Я использую версию: java.runtime.version = 1.8.0-b132

Дополнительные тесты:

LocalDate d = LocalDate.of(2014, 3, 1); // 2014-W09-6
System.out.println(
  "week-of-year in 2014-03-01: " 
  + d.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
System.out.println(
  "day-of-week in 2014-03-01: " 
  + d.get(ChronoField.DAY_OF_WEEK));

LocalDate later = d.plus(14, IsoFields.WEEK_BASED_YEARS); // 2028-03-02 = 2028-W09-4
System.out.println(
  "14 week-based-years later = " 
  + later);
System.out.println(
  "week-of-year in " + later + ": " 
  + later.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
System.out.println(
  "day-of-week in " + later + ": " 
  + later.get(ChronoField.DAY_OF_WEEK));

Вывод:

week-of-year in 2014-03-01: 9
day-of-week in 2014-03-01: 6
14 week-based-years later = 2028-03-02
week-of-year in 2028-03-02: 9
day-of-week in 2028-03-02: 4

Я не понимаю четкого правила. Ни день недели не сохраняется, ни день месяца не сохраняется при добавлении 14 недельных лет. Итак, это дополнительный вопрос: что такое правило за IsoFields.WEEK_BASED_YEARS? Возможно, команда JSR-310 может просветить нас?

4b9b3361

Ответ 1

Это ошибка в IsoFields, которой удалось проскользнуть, потому что этот метод был непроверен (извините за это). При правильной реализации должно быть очень мало различий между IsoFields и WeekFields.ISO.

См. отчет об ошибке и патч, который в конечном итоге будет работать через систему и будет исправлен.

Обратите внимание, что тестирование показало, что получение поля прекрасное, ошибка влияет только на метод with/adjustInto WEEK_BASED_YEAR. На устройство WEEK_BASED_YEARS влияет, потому что добавление реализовано внутри, повторно используя сломанный WEEK_BASED_YEAR.

Обновление 2014-08-28: Это была одна из 14 ошибок java.time исправлена ​​в 8u20.