В java.time как рассчитывается результат добавления месяца?

Каковы правила вычисления результата прибавления месяца к дате в JSR-310 java.time API в JDK 8. В частности, что произойдет, если вы добавите 1 месяц к такой дате, как 31 января?

LocalDate initial = LocalDate.of(2012, 1, 31);  // 31st January 2012
LocalDate result = initial.plusMonths(1);
// what is the result?

person JodaStephen    schedule 09.03.2014    source источник


Ответы (1)


Краткий ответ:

В примере результатом будет последний день февраля, 2012-02-29.

Объяснение:

Вопрос «какая дата получится, если добавить месяц» может быть открытым для интерпретации. Чтобы избежать этого, java.time API имеет очистить правило. Результат будет иметь тот же день месяца, что и ввод, если только это не будет недопустимой датой, и в этом случае результатом будет последний день месяца.

Таким образом, 31 января плюс один месяц дадут 31 февраля, но, поскольку это недопустимая дата, результатом будет последняя действительная дата в феврале, то есть 28 или 29 февраля, в зависимости от того, високосный ли это год:

// normal case
2011-01-15 plus 1 month = 2011-02-15  // 15 Jan -> 15 Feb

// special rule choosing the last valid day-of-month
2011-01-31 plus 1 month = 2011-02-28  // 31 Jan -> 28 Feb (2011 is normal year)
2012-01-31 plus 1 month = 2012-02-29  // 31 Jan -> 29 Feb (2012 is leap year)

// same rule applies for months other than February
2013-03-31 plus 1 month = 2013-04-30  // 31 Mar -> 30 Apr (only 30 days in April)

То же правило применяется при добавлении одного месяца или нескольких месяцев и всегда основывается на полученном месяце. т.е. сначала добавляется месяц (при необходимости корректируя год), и только потом учитывается день месяца. Это же правило действует и при вычитании.

// multiple months works on the month of the result
2013-10-31 plus 4 months = 2014-02-28   // last day of February
2013-10-31 minus 4 months = 2013-06-30  // last day of June

Те же правила действуют и при прибавлении/вычитании лет к/от даты - годы прибавляются, и только потом день месяца проверяется на достоверность в пределах месяца.

// years use the same rule
2012-02-29 plus 1 year = 2013-02-28  // 29th February invalid so adjusted to 28th

Если вашей бизнес-логике требуется другое правило для добавления месяца, лучший подход — написать TemporalAdjuster или TemporalAmount, которые упаковывают вашу специальную логику.

person JodaStephen    schedule 09.03.2014