Защо Java Calendar казва, че първият четвъртък от месеца е седмица 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. Може ли да има нещо общо с това, че седмица 1 няма четвъртък? Когато сложа 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)


Java Календар е снизходителен по подразбиране. Ако го зададете на 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