Какое наиболее чистое решение для добавления месяца к указанному дню с помощью LocalDateTime
или LocalDate
?
Хорошие ответы: В java.time как рассчитывается результат добавления месяца? и Найти следующее вхождение дня недели в JSR-310, поэтому я надеюсь, что эту проблему можно решить аналогичным чистым решением.
Допустим, пользователь выбирает день месяца (от 1 до 31) для некоторой периодической задачи. После выбора создается временная метка, которая увеличивается каждый месяц. Сохраняются только отметка времени текущего месяца (предыдущий месяц не отслеживается, отметка времени обновляется каждый месяц) и выбранный день месяца.
Если выбран день 31-е, и мы начинаем с 31 января, добавление месяца с dateTime.plusMonths(1)
методом дает 29 февраля в 2016 году. Если dateTime.plusMonths(1)
метод используется снова результат - 29 марта, а ожидаемый - 31 марта. Однако он работает с 1 по 28 число.
Обходной путь для 31-го числа месяца можно использовать с помощью dateTime.with(TemporalAdjusters.lastDayOfMonth())
, но это не распространяется на дни с 28-го по 30-е, которые также могут быть последними днями месяца.
Пример для lastDayOfMonth()
для выбранного дня месяца 30-го: 30 января, 29 февраля (поведение метода plusMonth выбирает последний день, если предыдущий день выше предыдущего месяц), 31 марта (ожидается 30-е, выбранный день месяца). Этот метод не учитывает выбранные дни месяца.
Конечно, у этой проблемы есть много потенциальных решений, которые включают некоторые проверки и вычисление разницы между месяцами и днями, но я ищу решение, использующее возможности java.time, только если это возможно.
Разъяснение
Я ищу способ перенести дату на следующий месяц с выбранным днем месяца. Вроде dateTime.plusMonths(1).withDayOfMonth(selectedDayOfMonth)
. Это вызовет исключение для таких дат, как 31 февраля, поскольку withDayOfMonth
переопределяет корректировку plusMonths
на последнюю действительную дату.
Пример итерации использования метода plusMonth
. В итерации берется значение из предыдущего - представьте себе рекурсию.
+-----------+------------------+---------------+
| iteration | Day-of-month: 31 | Expected |
+-----------+------------------+---------------+
| 1 | January 31st | January 31st |
| 2 | February 29th | February 29th |
| 3 | March 29th | March 31st |
| 4 | April 29th | April 30th |
+-----------+------------------+---------------+
И еще один рабочий пример для дня месяца с 1-го по 28-е.
+-----------+-------------------+--------------+
| iteration | Day-of-month: 4th | Expected |
+-----------+-------------------+--------------+
| 1 | January 4th | January 4th |
| 2 | February 4th | February 4th |
| 3 | March 4th | March 4th |
| 4 | April 4th | April 4th |
+-----------+-------------------+--------------+
29-й день месяца подходит для високосных лет, но не для обычных лет.
+-----------+--------------------+---------------+
| iteration | Day-of-month: 29th | Expected |
+-----------+--------------------+---------------+
| 1 | January 29th | January 29th |
| 2 | February 28th | February 28th |
| 3 | March 28th | March 29th |
| 4 | April 28th | April 29th |
+-----------+--------------------+---------------+
dateTime.plusMonths(1).with(lastDayOfMonth())
вероятно делает то, что вы хотите. - person assylias   schedule 20.08.2016