Вызов 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.

Ошибка парад ошибка #4328747

Вызов getTime перед сериализацией может быть достаточным, чтобы обойти ошибку, хотя у меня не достаточно установленной JVM, чтобы подтвердить это.

Другие вопросы по тегам