Почему календарь Java говорит, что первый четверг месяца - это неделя 5?

Я пытаюсь понять, как сделать будильник в определенный день недели. Вот пример кода, который печатает то, что я ожидаю:

  Calendar calendar = Calendar.getInstance();
  calendar.set(Calendar.WEEK_OF_MONTH, 1);
  System.out.println("Week of month: " + calendar.get(Calendar.WEEK_OF_MONTH)); // Week of month: 1

Но когда я добавляю это в код, я получаю результат, которого не понимаю:

  Calendar calendar = Calendar.getInstance();
  calendar.set(Calendar.DAY_OF_WEEK, Calendar.THURSDAY);
  calendar.set(Calendar.WEEK_OF_MONTH, 1);
  System.out.println("Week of month: " + calendar.get(Calendar.WEEK_OF_MONTH)); // Week of month: 5

Я пытаюсь установить будильник на определенный день на определенной неделе. Сегодня 15 июня 2013 года. Может кто-нибудь объяснить мне это. Время Joda не подходит для того, что я делаю, поэтому мне нужно, чтобы это работало с обычными библиотеками Java. Спасибо за помощь.

Примечание редактора

Приведенный выше код будет возвращать разные результаты в зависимости от даты его запуска, потому что Calendar.getInstance() возвращает календарь, установленный на текущее время. Для иллюстрации проблемы, которая не зависит от текущего времени, используйте это:

DateFormat dateFormat = DateFormat.getDateInstance();
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(1371294000000L);
System.out.println(dateFormat.format(calendar.getTime()));
calendar.set(Calendar.DAY_OF_WEEK, Calendar.THURSDAY);
System.out.println(dateFormat.format(calendar.getTime()));
calendar.set(Calendar.WEEK_OF_MONTH, 1);
System.out.println("Week of month: " + calendar.get(Calendar.WEEK_OF_MONTH)); 
System.out.println(dateFormat.format(calendar.getTime()));

Что выводит что-то вроде этого (по крайней мере, если ваш язык по умолчанию использует григорианский календарь):

Jun 15, 2013
Jun 13, 2013
Week of month: 5
May 30, 2013

person jhamm    schedule 15.06.2013    source источник
comment
Какой у вас часовой пояс? Для меня это печатает Week of month: 1   -  person jlordo    schedule 15.06.2013
comment
Восточное стандартное время. Я на атлантическом побережье. Я очистил свой проект и снова запустил его, но все равно получил 5. Может ли это быть как-то связано с тем, что на первой неделе нет четверга? Когда я ставлю 2, 3, 4, 5 вместо номера недели, я получаю то, что ожидаю.   -  person jhamm    schedule 15.06.2013
comment
Я также получаю Неделя месяца: 1 Вы точно скопировали свой код или перепечатали его с небольшой разницей?   -  person rossum    schedule 15.06.2013
comment
@jhamm: Вот именно. Это справедливо для вашей локали. Четверг первой недели этого месяца (июнь) - 30 мая.   -  person jlordo    schedule 15.06.2013
comment
Итак, как я могу программно установить будильник в аналогичном случае, когда первая неделя месяца приходится на пятницу, а я хочу, чтобы первый четверг был на второй неделе. Должен быть лучший способ!   -  person jhamm    schedule 15.06.2013
comment
Хочешь дать официальный ответ, чтобы я мог его принять?   -  person jhamm    schedule 15.06.2013
comment
@jhamm: Вы также можете принять письменный ответ;) Я не эксперт по локали ...   -  person jlordo    schedule 15.06.2013


Ответы (1)


Календарь снисходителен по умолчанию. Если вы установите его на 32 января, он переведет его на 1 февраля. Кроме того, определение «неделя» зависит от локали и немного сбивает с толку. Это очень подробно объясняется в документах JavaDocs, ссылка на которые приведена выше.

В вашем конкретном случае (или, по крайней мере, в моем регионе) неделя определяется как начинающаяся в воскресенье, а «первая неделя июня» определяется как период с воскресенья по субботу, который включает 1 июня. 1 июня 2013 г. — суббота. , последний день недели 22 2013 года. Воскресенье, 2 июня 2013 г., является первым днем ​​недели 2 июня, а не вторым днем ​​недели 1.

Поскольку на 1-й неделе июня нет четверга, снисходительный календарь интерпретирует DAY_OF_WEEK, THURSDAY как четверг 22-й недели 2013 года, то есть 30 мая 2013 года, то есть 5 недели мая, поэтому вы получить 5, а не 1 в вашем выводе.

Чтобы установить первый четверг июня, вам нужно:

 Calendar calendar = Calendar.getInstance();
 calendar.set(Calendar.MONTH, Calendar.JUNE);
 calendar.set(Calendar.DAY_OF_WEEK, Calendar.THURSDAY);
 calendar.set(Calendar.DAY_OF_WEEK_IN_MONTH, 1);

DAY_OF_WEEK_IN_MONTH может немного сбивать с толку. Вы используете его с DAY_OF_WEEK, чтобы указать, какое вхождение этого дня в этом месяце вы хотите. Таким образом, когда DAY_OF_WEEK установлен на четверг, DAY_OF_WEEK_IN_MONTH, 1 — это первый четверг месяца, DAY_OF_WEEK_IN_MONTH, 2 — второй четверг месяца и т. д. Это гораздо менее специфично для локали или открыто для (ошибочной) интерпретации, чем дни, составляющие первую неделю месяца. месяц.

person Old Pro    schedule 15.06.2013