Календарь Java - Дата непредсказуема после установки day_of_week

У меня есть следующий код в тесте JUnit, который, похоже, работал на прошлой неделе, не работает на этой неделе:

Calendar cal = Calendar.getInstance();
cal.set(2011, Calendar.JULY, 12);
cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY); // push the date to 15
System.out.println(cal.get(Calendar.DATE));

Как вы, вероятно, можете сделать вывод из моего комментария, поскольку 12-е число - вторник, я ожидаю, что Date будет 15 после установки DAY_OF_WEEK в пятницу. Однако напечатанное значение равно 22, что приводит к сбою теста.

Если я, однако, изменю код следующим образом и добавлю дополнительный вызов для получения:

Calendar cal = Calendar.getInstance();
cal.set(2011, Calendar.JULY, 12);
System.out.println(cal.get(Calendar.DATE));
cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY); // push the date to 15
System.out.println(cal.get(Calendar.DATE));

Я получаю вывод, который ожидаю, 12 и 15.

Кто-нибудь может объяснить, что происходит и почему этот тест работал на прошлой неделе?

12 голосов | спросил Jeshurun 17 J000000Sunday11 2011, 11:41:17

3 ответа


0

Первое, что нужно понять, это то, что Month + Day + DayOfWeek ничего не значит для Календаря. Календарь рассчитает истинное значение даты на основе

  

ГОД + МЕСЯЦ + ДАТА

или

  

ГОД + МЕСЯЦ + WEEK_OF_MONTH + DAY_OF_WEEK

(или некоторые другие комбинации, такие как год + день года и т. д.), поэтому Date + DayOfWeek по сути ничего не значит для него.

Второе, что нужно понять, это то, что когда вы устанавливаете календарь Java, он фактически не пересчитывает абсолютное время и не обновляет связанные поля, пока не произойдет операция, которая вызывает вычисления.

После первого набора календарь находится в конфликтном состоянии. Месяц и день говорят, что это 12 июля, но «неделя месяца» и «день недели» все еще говорят, что это сегодня, каким бы ни было сегодня. Затем вы называете установленный день недели в пятницу. Итак, теперь год, месяц и день, скажем, 12 июля, а поля «неделя месяца» и «день недели» говорят, что это пятница «этой» недели.

Правила календаря гласят, что последнее установленное поле «выигрывает» в случае конфликта, поэтому для вычисления других полей используются неделя месяца и день недели, например, пятница этой недели.

Вставка промежуточного элемента «исправляет» его, потому что он заставляет все внутреннее состояние календаря пересчитываться во вторник 12 июля перед установкой в ​​пятницу, поэтому внутренних конфликтов нет. «Неделя месяца» была установлена ​​на неделю, которая содержит 12 июля, путем пересчета до того, как вы установили день недели в пятницу.

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

Причина, по которой Джон сработал в комментариях, заключается в том, что он живет в Лондоне. Его компьютер думает, что недели начинаются по понедельникам. Таким образом, когда его спросили о пятнице «этой» недели, он все равно ответил 15 июля, когда его спросили в воскресенье 17 июля. Я говорю об этом, потому что разные первые дни недели в разных локалях - это просто еще один способ, с помощью которого попытки использовать поля WEEK_OF в календаре оказываются бесполезными.

ответил Affe 17 J000000Sunday11 2011, 12:00:50
0

Существует ошибка 4655637 (похоже на вашу проблему). Я проверил этот код в последней версии JDK6 (Windows), и у меня есть 15 в обоих случаях. Кстати, я предлагаю всегда использовать GregorianCalendar явно, если вы не хотите что-то еще (в зависимости от вашей локали).

ответил Grzegorz Szpetkowski 17 J000000Sunday11 2011, 12:00:31
0

РЕДАКТИРОВАТЬ: официальные документы :

  

Ниже приведены комбинации полей календаря по умолчанию.   самая последняя комбинация, определенная самым последним установленным синглом   поле, будет использоваться.

     

Для полей даты:

 YEAR + MONTH + DAY_OF_MONTH
 YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
 YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
 YEAR + DAY_OF_YEAR
 YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
     

Для полей времени:

 HOUR_OF_DAY
 AM_PM + HOUR

В дополнение к четкому ответу @ Affe, следующие комбинации, похоже, работают (по ссылке на сообщение об ошибке @ GrzegorzSzpetkowski)

  

Календарь ожидает следующих комбинаций полей для определения   свидание.

 MONTH + DAY_OF_MONTH
 MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
 MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
 DAY_OF_YEAR
 DAY_OF_WEEK + WEEK_OF_YEAR
     

Когда вы устанавливаете DAY_OF_WEEK, календарь ожидает поле недели   (WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH или WEEK_OF_YEAR) также был   задавать. Поэтому избегайте установки DAY_OF_WEEK без установки одной недели   поля.

ответил serv-inc 4 J000000Saturday15 2015, 14:23:08

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132