PlusDays: примеры (JAVA)
plusDays(long daysToAdd): LocalDateКраткое описание
Метод plusDays добавляет к дате или к типу даты-времени указанное количество дней и возвращает новый объект с результатом. В Java реализация встречается в нескольких классах и интерфейсах пакета java.time: в LocalDate, LocalDateTime, ZonedDateTime, OffsetDateTime и у некоторых других типов. Также близкая по смыслу операция доступна через Period (для представления интервала) и через универсальные методы с указанием единицы времени (plus(long, TemporalUnit)).
Метод неизменяемый: исходный объект не меняет состояние, возвращается новый экземпляр с изменённой датой.
Аргументы и возвращаемые значения
- Аргумент: как правило один числовой параметр - количество дней. В
LocalDateи подобных этоlong daysToAdd. ВPeriodметоды прибавления принимаютintили используются фабричные методы. - Значения: возвращается новый экземпляр того же типа (например,
LocalDateдляLocalDate.plusDays), где к исходной дате добавлено указанное количество дней. При отрицательном аргументе происходит вычитание дней.
Поведение и ограничения
- Обработка смены месяца и года автоматическая: при переходе через границы месяцев и года результат корректно сдвигается.
- Высокосные года учитываются: добавление 1 дня к
2020-02-28даёт2020-02-29. - Для типов с часовым поясом (
ZonedDateTime) при переходе через летнее/зимнее время может измениться смещение (offset). Добавление суток понимается как сдвиг календарной даты, а не как фиксированные 24 часа. - При превышении допустимого диапазона дат метод выбрасывает исключение (как правило
DateTimeExceptionилиArithmeticExceptionпри переполнении арифметики).
Исключения
DateTimeExceptionпри выходе за поддерживаемый диапазон дат.ArithmeticExceptionпри переполнении арифметики при больших значениях.
Примеры использования
Короткие примеры для различных типов. Каждый пример содержит код и результат.
LocalDate: базовая операция и высокосный год
java.time.LocalDate d = java.time.LocalDate.of(2020, 2, 28);
java.time.LocalDate r = d.plusDays(1);
System.out.println(r);
2020-02-29
LocalDate с отрицательным значением
java.time.LocalDate d2 = java.time.LocalDate.of(2021, 3, 1);
System.out.println(d2.plusDays(-1));
2021-02-28
LocalDateTime: время сохраняется
java.time.LocalDateTime dt = java.time.LocalDateTime.of(2021, 12, 31, 23, 0);
systemOut(dt.plusDays(1));
// утилита вывода
static void systemOut(java.time.LocalDateTime x){ System.out.println(x); }
2022-01-01T23:00
ZonedDateTime и переход на летнее время
java.time.ZonedDateTime z = java.time.ZonedDateTime.of(
2021, 3, 27, 12, 0, 0, 0, java.time.ZoneId.of("Europe/Berlin")
);
System.out.println(z);
System.out.println(z.plusDays(1));
2021-03-27T12:00+01:00[Europe/Berlin] 2021-03-28T12:00+02:00[Europe/Berlin]
Period: создание интервала и прибавление дней к интервалу
java.time.Period p = java.time.Period.ofMonths(1);
java.time.Period p2 = p.plusDays(10);
System.out.println(p2);
P1M10D
LocalDate с Period
java.time.LocalDate d3 = java.time.LocalDate.of(2021, 1, 31);
java.time.LocalDate res = d3.plus(java.time.Period.ofMonths(1)).plusDays(1);
System.out.println(res);
2021-03-01
Похожие методы в Java
- plus(long, TemporalUnit) - универсальный метод для добавления любой единицы времени, например
date.plus(5, java.time.temporal.ChronoUnit.DAYS). Предпочтение можно отдать при генерализации кода или когда единица времени определяется динамически. - plusWeeks/plusMonths/plusYears - более семантически точные методы для добавления недель, месяцев или лет. При добавлении недель используются недели как группы по 7 дней.
- Calendar.add (старый API) - добавление дней через
Calendar.add(Calendar.DAY_OF_MONTH, n). Старый API мутирует объект и требует осторожности при многопоточной работе. - Instant/Duration - для представлений в виде наносекунд/секунд. Если важны точные 24-часовые интервалы, лучше использовать
Duration.ofHours(24)иinstant.plus(duration)вместо добавления календарных дней.
Аналоги в других языках и отличия
- JavaScript (классический Date)
const d = new Date('2021-03-27T12:00:00Z');
d.setUTCDate(d.getUTCDate() + 1);
console.log(d.toISOString());
2021-03-28T12:00:00.000Z
Отличие: объект Date является мутабельным, операции часто изменяют исходный объект. Также нужно учитывать часовой пояс и методы UTC vs локальные.
// если доступен
const pd = new Temporal.PlainDate(2021, 3, 27);
console.log(pd.plus({ days: 1 }).toString());
2021-03-28
from datetime import date, timedelta
print(date(2020,2,28) + timedelta(days=1))
2020-02-29
Отличие: в Python операция с timedelta похожа по семантике; объекты дат также неизменяемы и возвращается новый объект.
$d = new DateTime('2021-03-27');
$d->modify('+1 day');
echo $d->format('Y-m-d');
2021-03-28
Отличие: DateTime в PHP по умолчанию мутирует объект при вызове modify, но можно клонировать.
-- MySQL
SELECT DATE_ADD('2021-03-27', INTERVAL 1 DAY);
-- SQL Server
SELECT DATEADD(day, 1, '2021-03-27');
2021-03-28 2021-03-28
var d = new DateTime(2021,3,27);
Console.WriteLine(d.AddDays(1).ToString("yyyy-MM-dd"));
2021-03-28
Отличие: API C# схож по семантике с Java Time - объекты DateTime неизменяемы, возвращается новый объект.
t := time.Date(2021, 3, 27, 12, 0, 0, 0, time.UTC)
fmt.Println(t.AddDate(0, 0, 1))
2021-03-28 12:00:00 +0000 UTC
val d = java.time.LocalDate.of(2021,3,27)
println(d.plusDays(1))
2021-03-28
Отличие: Kotlin использует тот же Java Time API на JVM, методы идентичны.
-- пример с использованием os.time/os.date
local t = {year=2021, month=3, day=27, hour=12}
local sec = os.time(t) + 24*60*60
print(os.date('%Y-%m-%d', sec))
2021-03-28
Отличие: в Lua нет встроенного богатого календарного API, используется смещение в секундах; это не всегда равно добавлению календарного дня при переходе через летнее время.
Типичные ошибки и примеры
-
Ожидание мутации объекта: java.time объекты неизменяемы, поэтому вызов
d.plusDays(1)без присвоения не изменит исходную переменную.java.time.LocalDate d = java.time.LocalDate.of(2021, 1, 1); d.plusDays(1); System.out.println(d);2021-01-01
Правильное использование:
d = d.plusDays(1)или сохранять результат в другую переменную. -
Путаница между «днём календаря» и «24 часами»:
java.time.ZonedDateTime z = java.time.ZonedDateTime.of( 2021,3,27,12,0,0,0, java.time.ZoneId.of("Europe/Berlin") ); System.out.println(z.plusDays(1)); System.out.println(z.plus(java.time.Duration.ofHours(24)));2021-03-28T12:00+02:00[Europe/Berlin] 2021-03-28T13:00+02:00[Europe/Berlin]
Добавление календарного дня сохраняет локальное время, а добавление Duration в секундах/часах учитывает переходы и может дать другой результат по времени.
-
Выход за диапазон дат:
try { java.time.LocalDate dmax = java.time.LocalDate.MAX; System.out.println(dmax.plusDays(1)); } catch (Exception e) { e.printStackTrace(); }java.time.DateTimeException: Invalid date after addition at ...При операции, приводящей к дате вне допустимого диапазона, генерируется исключение. Следует предусмотреть обработку или валидацию входных значений.
-
Передача null: если метод вызывается у null-ссылки, произойдёт
NullPointerException. Например,LocalDate d = null; d.plusDays(1);вызовет NPE.
Изменения и история
Метод plusDays введён в рамках Java 8 как часть нового пакета java.time. С тех пор явных изменений в семантике метода не произошло: он остаётся неизменяемым, корректно обрабатывает переходы календаря и летнее/зимнее время для типов с часовыми поясами. Дополнительные утилиты и методы вокруг времени постепенно добавлялись в последующих версиях Java, но поведение plusDays совместимо назад.
Расширенные и редкие варианты использования
Несколько продвинутых сценариев с объяснениями.
Комбинация Period и Duration для сложных сдвигов
java.time.ZonedDateTime start = java.time.ZonedDateTime.of(
2021, 10, 30, 1, 30, 0, 0, java.time.ZoneId.of("Europe/Berlin")
);
// добавить 1 календарный день и 36 часов
java.time.ZonedDateTime r = start.plus(java.time.Period.ofDays(1)).plus(java.time.Duration.ofHours(36));
System.out.println(start);
System.out.println(r);
2021-10-30T01:30+02:00[Europe/Berlin] 2021-11-01T13:30+01:00[Europe/Berlin]
Пояснение: при комбинировании календарных и фиксированных интервалов учитываются переходы смещений и суммируются шаги отдельно.
Использование с нестандартной хронологией (не-ISO)
java.time.chrono.HijrahDate hd = java.time.chrono.HijrahChronology.INSTANCE.dateNow();
java.time.chrono.HijrahDate hd2 = hd.plus(java.time.temporal.ChronoUnit.DAYS.getDuration().toDays(), java.time.temporal.ChronoUnit.DAYS);
// рекомендуется использовать типизированный plus с ChronoUnit
System.out.println(hd);
System.out.println(hd.plus(10, java.time.temporal.ChronoUnit.DAYS));
(пример вывода зависит от текущей даты в хиджре) (дата +10 дней в хиджрском календаре)
Пояснение: в нестандартных календарях добавление дней ведёт себя согласно правилам этой хроники, поэтому результаты отличаются от эквивалентных ISO-операций.
Атомарная проверка валидности перед добавлением
java.time.LocalDate safeAdd(java.time.LocalDate d, long days){
// проверка переполнения по диапазону
long maxAdd = java.time.LocalDate.MAX.toEpochDay() - d.toEpochDay();
long minAdd = java.time.LocalDate.MIN.toEpochDay() - d.toEpochDay();
if (days > maxAdd || days < minAdd) throw new IllegalArgumentException("out of range");
return d.plusDays(days);
}
// использование
System.out.println(safeAdd(java.time.LocalDate.of(9999,12,31), -1));
9999-12-30
Пояснение: вычисление в днях через toEpochDay() позволяет заранее проверить выход за диапазон.
Отличие при добавлении 24 часов и одного календарного дня
java.time.ZonedDateTime z0 = java.time.ZonedDateTime.of(2021,3,27,0,30,0,0, java.time.ZoneId.of("Europe/Berlin"));
System.out.println(z0.plusDays(1));
System.out.println(z0.plus(java.time.Duration.ofHours(24)));
2021-03-28T00:30+02:00[Europe/Berlin] 2021-03-28T01:30+02:00[Europe/Berlin]
Пояснение: переход на летнее время сдвинул часы, поэтому фиксированное количество часов даёт другой локальный момент по сравнению с календарной операцией.
Обработка больших интервалов и поточность
// пример, когда требуется прибавлять много дней в цикле, лучше использовать арифметику с epoch
java.time.LocalDate base = java.time.LocalDate.of(2000,1,1);
long daysToAdd = 10_000_000L;
java.time.LocalDate result = java.time.LocalDate.ofEpochDay(base.toEpochDay() + daysToAdd);
System.out.println(result);
(результат в зависимости от вычисления, возможно выброс исключения при выходе за диапазон)
Пояснение: при экстремально больших значениях стоит учитывать производительность и возможность переполнения; работа через epoch дни даёт контроль и возможность ранней проверки.