Странное поведение с GregorianCalendar

Я просто встретился со странным поведением с классом GregorianCalendar, и я задавался вопросом, делал ли я действительно что-то плохо.

Это только добавляет, когда месяц даты инициализации имеет actualMaximum большее, чем месяц, я собираюсь установить календарь на.

Вот пример кода:

    // today is 2010/05/31  
    GregorianCalendar cal = new GregorianCalendar();

    cal.set(Calendar.YEAR, 2010);
    cal.set(Calendar.MONTH, 1); // FEBRUARY

    cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    cal.set(Calendar.HOUR_OF_DAY, cal.getActualMaximum(Calendar.HOUR_OF_DAY));
    cal.set(Calendar.MINUTE, cal.getActualMaximum(Calendar.MINUTE));
    cal.set(Calendar.SECOND, cal.getActualMaximum(Calendar.SECOND));
    cal.set(Calendar.MILLISECOND, cal.getActualMaximum(Calendar.MILLISECOND));

    return cal.getTime(); // => 2010/03/03, wtf

Я знаю, что проблема вызывается тем, что календарная дата инициализации является 31-дневным месяцем (может), которые смешивают с набором месяца до февраля (28 дней). Фиксация легка (просто устанавливает day_of_month на 1 прежде, чем установить год и месяц), но я задавался вопросом, это действительно было требуемым поведением. Какие-либо мысли?

14
задан BalusC 31 May 2010 в 16:16
поделиться

4 ответа

Получает фактические максимумы текущей даты / времени. В мае 31 день, что на 3 больше, чем 28 февраля, и поэтому он переместится на 3 марта.

Вам необходимо вызвать Calendar # clear () после его получения / создания:

GregorianCalendar cal = new GregorianCalendar();
cal.clear();
// ...

В результате получится:

Sun Feb 28 23:59:59 GMT-04:00 2010

(что соответствует моему часовому поясу)

Как сказано в одном из ответов, java.util.Calendar и Date - эпические неудачи. Рассмотрите JodaTime при выполнении интенсивных операций с датой и временем.

14
ответ дан 1 December 2019 в 13:08
поделиться

Я уверен, что это нежелательное поведение. Я точно так же уверен, что никто не продумал этот вариант использования, когда создавал класс. Дело в том, что Calendar имеет очень большую проблему с внутренним состоянием и тем, как он управляет всеми потенциальными переходами во всех установленных методах.

Если вы не можете использовать JodaTime или JSR-310 в своем проекте, тщательно протестируйте модуль при использовании класса Calendar. Как вы можете видеть, в этом случае код календаря ведет себя по-разному в зависимости от того, в какой день месяца (или в какое время дня) вы запускаете код.

2
ответ дан 1 December 2019 в 13:08
поделиться

Возможно, setLenient(boolean lenient) поможет вам разобраться с этим. Я получаю исключение, когда запускаю код ниже.

Если нет, то Joda - лучший ответ.

import java.util.Calendar;

public class CalTest
{
    public static void main(String[] args)
    {
        // today is 2010/05/31
        Calendar cal = Calendar.getInstance();
        cal.setLenient(false);

        cal.set(Calendar.YEAR, 2010);
        cal.set(Calendar.MONTH, 1); // FEBRUARY

        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.HOUR_OF_DAY, cal.getActualMaximum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getActualMaximum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getActualMaximum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, cal.getActualMaximum(Calendar.MILLISECOND));

        System.out.println(cal.getTime());
    }
}
1
ответ дан 1 December 2019 в 13:08
поделиться

Да, именно так это и должно работать. Если вы начнете с GregorianCalendar, имеющего точную дату, и измените его, сделав непоследовательным, то вам не следует доверять полученным результатам.

В документации к getActualMaximum(...) говорится:

Например, если дата этого экземпляра - 1 февраля 2004 года, то фактическое максимальное значение поля DAY_OF_MONTH равно 29, поскольку 2004 год - високосный, а если дата этого экземпляра - 1 февраля 2005 года, то 28.

Таким образом, это должно работать, но вы должны кормить его последовательными значениями. 31 февраля 2010 не является корректным и применение вещей, которые полагаются на значение даты (например, getActualMaximum) не может работать. Как оно должно исправить это самостоятельно? Решив, что месяц неправильный? Или что день неправильный?

Кстати, как все всегда говорят, используйте JodaTime... :)

2
ответ дан 1 December 2019 в 13:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: