Вызов Java Calendar.getTime() необходим для обновления объекта?
Я наткнулся на комментарий в некотором коде Java, который утверждает, что getTime()
необходимо вызвать, чтобы обновить Calendar
объект. Это правда? Я не могу найти ничего, что говорит, что это необходимо.
Вот код:
Calendar cal = new GregorianCalendar();
cal.setFirstDayOfWeek(Calendar.SUNDAY);
cal.set(2009, 9 - 1, 10, 2, 30);
// Get Time needs to be called to update the Calendar object
cal.getTime();
5 ответов
cal.getTime()
действительно нужно вызывать, чтобы пересчитать его внутренности. Это очень странное поведение для API, но в явном виде в Календаре это явно указано:
Получение и установка значений полей календаря
Значения полей календаря можно установить, вызвав методы set. Любые значения полей, установленные в Календаре, не будут интерпретироваться до тех пор, пока ему не понадобится рассчитать значение времени (в миллисекундах с начала эпохи) или значения полей календаря. Вызов get, getTimeInMillis, getTime, add and roll включает в себя такие вычисления.
...
Полевая Манипуляция
Поля календаря можно изменить тремя способами: set(), add() и roll(). set(f, value) меняет поле календаря f на значение. Кроме того, он устанавливает внутреннюю переменную-член, чтобы указать, что поле календаря f было изменено. Хотя поле календаря f изменяется немедленно, значение времени календаря в миллисекундах не пересчитывается до следующего вызова get(), getTime(), getTimeInMillis(), add() или roll (). Таким образом, множественные вызовы set () не запускают несколько ненужных вычислений. В результате изменения поля календаря с помощью set () другие поля календаря также могут изменяться в зависимости от поля календаря, значения поля календаря и системы календаря. Кроме того, get(f) не обязательно вернет значение, установленное вызовом метода set, после пересчета полей календаря. Специфика определяется конкретным календарным классом.
Поведение является неожиданным и не всегда происходит, но следующие модульные тесты должны иллюстрировать это поведение и всегда происходить.
/**
* Fails the assertion due to missing getTime()
* @throws ParseException
*/
public class DateTest {
@Test
public void testNoGetTime() throws ParseException {
DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
Date testDate = df.parse("04/15/2013");
Calendar testCal = Calendar.getInstance();
testCal.setTime(testDate);
Date expectedDate = df.parse("04/04/2013");
Date actualDate = null;
testCal.set(Calendar.DAY_OF_MONTH, testCal.getMinimum(Calendar.DAY_OF_MONTH));
//testCal.getTime();
testCal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
testCal.add(Calendar.DAY_OF_MONTH, -1);
actualDate = testCal.getTime();
assertEquals("Dates should be equal", expectedDate.toString(), actualDate.toString());
}
@Test
public void testWithGetTime() throws ParseException {
DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
Date testDate = df.parse("04/15/2013");
Calendar testCal = Calendar.getInstance();
testCal.setTime(testDate);
Date expectedDate = df.parse("04/04/2013");
Date actualDate = null;
testCal.set(Calendar.DAY_OF_MONTH, testCal.getMinimum(Calendar.DAY_OF_MONTH));
testCal.getTime();
testCal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
testCal.add(Calendar.DAY_OF_MONTH, -1);
actualDate = testCal.getTime();
assertEquals("Dates should be equal", expectedDate.toString(), actualDate.toString());
}
}
@skaffman Ответ НЕ ПРАВИЛЬНЫЙ.
Вот пример, который доказывает то, что я говорю.
//Create an Calendar object set to todays date & time
Calendar calendar = Calendar.getInstance();
Log.d(Tag, "Now : "+ calendar.toString());
//Set the Calendar to the first day of Month
calendar.set(Calendar.DAY_OF_MONTH,1);
Log.d(Tag, "Calendar.DAY_OF_MONTH,1: "+ calendar.toString());
Это вывод Log.d:
Now : java.util.GregorianCalendar[time=1478834995641,areFieldsSet=true,lenient=true,zone=America/Chicago,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2016,MONTH=10,WEEK_OF_YEAR=46,WEEK_OF_MONTH=2,DAY_OF_MONTH=10,DAY_OF_YEAR=315,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=29,SECOND=55,MILLISECOND=641,ZONE_OFFSET=-21600000,DST_OFFSET=0] Calendar.DAY_OF_MONTH,1:
Calendar.DAY_OF_MONTH,1: java.util.GregorianCalendar[time=?,areFieldsSet=false,lenient=true,zone=America/Chicago,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2016,MONTH=10,WEEK_OF_YEAR=46,WEEK_OF_MONTH=2,DAY_OF_MONTH=1,DAY_OF_YEAR=315,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=29,SECOND=55,MILLISECOND=641,ZONE_OFFSET=-21600000,DST_OFFSET=0]
Если у вас есть время, чтобы проверить это: Календарь в начале показывает:
time=1478834995641
DAY_OF_MONTH=10
DAY_OF_YEAR=315
Однако, когда вы установите его на первый день месяца:
time=?
DAY_OF_MONTH=1
DAY_OF_YEAR=315
Да, первый день месяца изменился так, как мы хотели, но некоторые атрибуты остались прежними. Например, как это получается, мы устанавливаем календарь на DAY_OF_MONTH=1
но мы все еще в DAY_OF_YEAR=315
,
Если мы будем использовать любую из следующих функций, это заставит Календарь обновляться.
Вызов get, getTimeInMillis, getTime, add and roll.
Из класса календаря в Javadocs Проверьте: Получение и установка значений полей календаря
Чтобы исправить это, мы добавим следующий код calendar.getTimeInMillis();
что заставляет Календарь обновлять свои атрибуты.
//Create an Calendar object set to todays date & time
Calendar calendar = Calendar.getInstance();
Log.d(Tag, "Now : "+ calendar.toString());
//Set the Calendar to the first day of Month
calendar.set(Calendar.DAY_OF_MONTH,1);
//UPDATE BY CALLING getTimeInMillis() or any of the previously mentioned functions
calendar.getTimeInMillis();
Log.d(Tag, "Calendar.DAY_OF_MONTH,1: "+ calendar.toString());
Теперь давайте проверим результаты:
Now : java.util.GregorianCalendar[time=1478836452183,areFieldsSet=true,lenient=true,zone=America/Chicago,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2016,MONTH=10,WEEK_OF_YEAR=46,WEEK_OF_MONTH=2,DAY_OF_MONTH=10,DAY_OF_YEAR=315,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=54,SECOND=12,MILLISECOND=183,ZONE_OFFSET=-21600000,DST_OFFSET=0]
Calendar.DAY_OF_MONTH,1: java.util.GregorianCalendar[time=1478055252183,areFieldsSet=true,lenient=true,zone=America/Chicago,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2016,MONTH=10,WEEK_OF_YEAR=45,WEEK_OF_MONTH=1,DAY_OF_MONTH=1,DAY_OF_YEAR=306,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=54,SECOND=12,MILLISECOND=183,ZONE_OFFSET=-21600000,DST_OFFSET=3600000]
Поэтому @skaffman Ответ не правильный, как на ваш вопрос Calendar.getTime();
действительно необходимо, если вы не хотите получать странные значения в какой-то момент.
Возможно, вы нажали Bug ID 4851640
Вызов get(...) / getTime() для экземпляра Calendar делает isSet(...) бесполезным!
Нет, это не должно быть необходимо.
Был ли календарь сериализован сразу после этого?
Я был пойман ошибкой с сериализацией Календаря в более старых jvms.
Вызов getTime перед сериализацией может быть достаточным, чтобы обойти ошибку, хотя у меня не достаточно установленной JVM, чтобы подтвердить это.