Задача календаря ГОД

Я пробовал следующий фрагмент кода:

Calendar c1 = Calendar.getInstance();
c1.set(Calendar.YEAR, 0);
c1.set(Calendar.DAY_OF_YEAR, 1);
Date d1 = c1.getTime();

Calendar c2 = Calendar.getInstance();
c2.setTime(d1);
c2.set(Calendar.YEAR, 2001);
c2.set(Calendar.DAY_OF_YEAR, 1);
System.out.println(c2.getTime().toString());

Calendar c3 = Calendar.getInstance();
c3.set(Calendar.YEAR, 2000);
c3.set(Calendar.DAY_OF_YEAR, 1);
Date d2 = c3.getTime();

Calendar c4 = Calendar.getInstance();
c4.setTime(d2);
c4.set(Calendar.YEAR, 2001);
c4.set(Calendar.DAY_OF_YEAR, 1);
System.out.println(c4.getTime().toString());

Результат:

Wed Jan 01 23:47:00 CET 2001
Mon Jan 01 23:47:00 CET 2001

Что не так? Не следует ли использовать календарь таким образом для установки YEAR?

Ответ 1

Год относится к эпохе. Устанавливая год на что-то меньшее или равное 0, календарь автоматически корректирует это, переключая эру (от AD до BC или от BC до AD). Такое поведение лучше известно из других полей. Например. если вы установите месяц на что-то отрицательное, год будет уменьшаться соответствующим образом.

Эти исправления не производятся индивидуально, но они делаются все сразу, обычно, когда вы вызываете getTime() для считывания итоговой даты.

Calendar c1 = Calendar.getInstance(); // August  16th, 2012 AD
c1.set(Calendar.YEAR, 0);             // August  16th,    0 AD
c1.set(Calendar.DAY_OF_YEAR, 1);      // January  1st,    0 AD
Date d1 = c1.getTime();               // January  1st,    1 BC (corrected)

Calendar c2 = Calendar.getInstance();
c2.setTime(d1);
c2.set(Calendar.YEAR, 2001);          // January  1st, 2001 BC
c2.set(Calendar.DAY_OF_YEAR, 1);
System.out.println(c2.getTime());     // prints "Wed Jan 01 05:35:00 CET 2001"
                                      // because 01/01/2001 BC was a Wednesday

Поэтому вместо того, чтобы устанавливать год к 2001 году, вам нужно установить его на -2000 (потому что год 0 вообще не существует). Или вы можете явно задать эру:

c2.set(Calendar.ERA, GregorianCalendar.AD);

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

Calendar c1 = Calendar.getInstance(); // August  16th, 2012 AD
c1.set(Calendar.YEAR, 0);             // August  16th,    0 AD
c1.set(Calendar.DAY_OF_YEAR, 1);      // January  1st,    0 AD
c1.set(Calendar.YEAR, 2001);          // January  1st, 2001 AD
System.out.println(c1.getTime());     // prints the expected date

Чтобы вывести эру даты, вы можете использовать "G" в шаблоне SimpleDateFormat:

new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy G").format(c2.getTime())
// "Wed Jan 01 05:35:00 CET 2001 BC"

Ответ 2

В обоих случаях, непосредственно перед печатью вывода, вы устанавливаете год до 2001 года. В обоих случаях результат отражается в этом году. Вы ожидали другого выхода?