Я просто встретился со странным поведением с классом 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 прежде, чем установить год и месяц), но я задавался вопросом, это действительно было требуемым поведением. Какие-либо мысли?
Получает фактические максимумы текущей даты / времени. В мае 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 при выполнении интенсивных операций с датой и временем.
Я уверен, что это нежелательное поведение. Я точно так же уверен, что никто не продумал этот вариант использования, когда создавал класс. Дело в том, что Calendar имеет очень большую проблему с внутренним состоянием и тем, как он управляет всеми потенциальными переходами во всех установленных методах.
Если вы не можете использовать JodaTime или JSR-310 в своем проекте, тщательно протестируйте модуль при использовании класса Calendar. Как вы можете видеть, в этом случае код календаря ведет себя по-разному в зависимости от того, в какой день месяца (или в какое время дня) вы запускаете код.
Возможно, 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());
}
}
Да, именно так это и должно работать. Если вы начнете с GregorianCalendar
, имеющего точную дату, и измените его, сделав непоследовательным, то вам не следует доверять полученным результатам.
В документации к getActualMaximum(...)
говорится:
Например, если дата этого экземпляра - 1 февраля 2004 года, то фактическое максимальное значение поля DAY_OF_MONTH равно 29, поскольку 2004 год - високосный, а если дата этого экземпляра - 1 февраля 2005 года, то 28.
Таким образом, это должно работать, но вы должны кормить его последовательными значениями. 31 февраля 2010 не является корректным и применение вещей, которые полагаются на значение даты (например, getActualMaximum
) не может работать. Как оно должно исправить это самостоятельно? Решив, что месяц неправильный? Или что день неправильный?
Кстати, как все всегда говорят, используйте JodaTime... :)