Месяц отключен на один (не из-за того, что он основан на 0)
Когда я устанавливаю месяц на дату, представляющую 1/1/1970, а затем сразу возвращаю месяц назад, он отключается на один.
import java.util.Date;
@Test
public void monthShouldBeExpectedValue() {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(0));
int expectedMonth = Calendar.JUNE;
calendar.set(Calendar.MONTH, expectedMonth);
int actualMonth = calendar.get(Calendar.MONTH);
assertThat(actualMonth, equalTo(expectedMonth)); // test fails: expected 5 got 6
}
Если я изменю эту строку
calendar.setTime(new Date(0));
к
calendar.setTime(new Date()); // use 'today' instead of 1/1/1970
то тест проходит. Кто-нибудь знает, почему?
Edit
Печатная версия дат:
new Date(0): Wed Dec 31 19:00:00 EST 1969
date from calendar: Tue Jul 01 19:00:00 EDT 1969
Я запускаю старый JDK: 1.6.0_30-b12 (64 бит)
Я в восточном стандартном времени.
Ответы
Ответ 1
Мое предположение заключается в том, что из-за вашего текущего часового пояса время интерпретируется как 31 декабря 1969 года + куча часов. Таким образом, месяц установки к июню должен был произойти 31 июня 1969 года (которого не существует, в июне - 30 дней). Поэтому он перейдет к июлю.
Ответ 2
Прежде всего, напечатайте календарь, чтобы иметь точную дату.
Тогда обычные вопросы:
Какой ваш часовой пояс?
Есть ли у вас летняя экономия времени?
Сменился ли часовой пояс с 1970 года?
обычно проблема заключается в том, что вместо полуночи в первый месяц вы получаете на один час меньше, то есть поздно ночью в последний день последнего месяца.
Ответ 3
Ответ Smallhacker верен.
Joda времени
Для удовольствия я попробовал аналогичный код в Joda-Time 2.3.
Такое же поведение имеет смысл. Если вы попросите DateTime, построенный с миллисекунды-от-эпохи нуля, вы начинаете с 1 января 1970 года. Но это дата-время в UTC (без смещения часового пояса).
Если вы вызываете toString() в этом объекте DateTime с использованием пользовательского часового пояса пользователя, конечно, вы видите другое значение, отличное от Epoch (начало дня 1 января 1970 года). Если пользователь исландский, где они используют UTC круглый год.
Пример кода
DateTime epoch = new DateTime( 0 );
System.out.println( "epoch: " + zero );
System.out.println( "epoch in UTC: " + zero.toDateTime( DateTimeZone.UTC ) );
При запуске в часовом поясе по умолчанию на западном побережье США...
epoch: 1969-12-31T16:00:00.000-08:00
epoch in UTC: 1970-01-01T00:00:00.000Z
Мораль истории
Всегда указывать часовой пояс; никогда не предполагайте.
Работа с значениями даты и времени без явных известных часовых поясов подобна работе над текстовыми файлами без явной кодировки символов. Не умный.
Июнь
Чтобы ответить на ваш вопрос, но используя Joda-Time в одной строке кода...
System.out.println( "June after Epoch: " + new DateTime( 0 ).toDateTime( DateTimeZone.UTC ).monthOfYear().setCopy( DateTimeConstants.JUNE ) );
При запуске...
June after Epoch: 1970-06-01T00:00:00.000Z
Этот же код достаточно умен, чтобы обрабатывать конец месяца. Если оригинал был 31 января, результатом будет 30 июня.