date_modify()
Полное руководство по функции PHP date_modify: синтаксис, примеры, подводные камни при работе с месяцами и использование DateTimeImmutable.
В этом руководстве рассматривается метод PHP DateTime::modify() — объектно-ориентированный аналог процедурной функции date_modify(). Объясняется, как modify() разбирает строки относительных дат, что он возвращает, в чём заключается проблема переполнения месяца, с которой сталкивается большинство разработчиков, и как избежать случайного изменения даты.
Что такое DateTime::modify()?
modify() — встроенный метод класса DateTime, который изменяет хранимую дату/время с помощью строки в относительном формате, например +10 days, -3 months или next monday. Используйте его всякий раз, когда вам нужна арифметика дат — сдвиг дедлайна вперёд, перемотка временной метки назад или переход к следующему рабочему дню — без ручного вычисления секунд.
Два свойства выделяют modify() среди остальных методов; запомните их прежде, чем переходить к примерам:
- Он изменяет объект на месте — меняет тот же
DateTime, на котором вызван, а не возвращает новую копию. - Он принимает ту же грамматику относительных форматов, которую PHP использует при создании дат из строк, поэтому всё, что понимает
new DateTime('+1 week'), понимает иmodify().
Синтаксис
public DateTime::modify(string $modifier): DateTime|false$modifier— строка в относительном формате (например,+1 day,-2 weeks,first day of next month,14:00).- Возвращает тот же object
DateTimeв случае успеха (что позволяет строить цепочки вызовов) илиfalseпри ошибке (например, если строка не может быть разобрана).
Поскольку метод возвращает сам объект, следующие две строки эквивалентны — исходный $date изменяется в любом случае:
$date->modify('+1 day'); // mutates $date, return value ignored
$date = $date->modify('+1 day'); // mutates $date AND reassigns the same objectСовет: Если $modifier поступает из пользовательского ввода, всегда проверяйте результат на false перед использованием — неверно сформированная строка вернёт false, а не выбросит исключение.
Примеры
Пример 1: Прибавление дней к дате
Прибавление 10 дней к фиксированной дате с базовой обработкой ошибок:
Прибавление дней к дате в PHP
Вывод:
2023-03-11Пример 2: Вычитание месяцев из даты
Вычитание 3 месяцев из фиксированной даты:
Вычитание месяцев из даты в PHP
Вывод:
2022-12-01Пример 3: Установка времени в конкретное значение
Установка времени на 14:00 для фиксированной даты:
Установка времени в конкретное значение в PHP
Вывод:
2023-03-01 14:00:00Обратите внимание: modify('14:00') устанавливает время на 14:00, не затрагивая дату — относительные форматы, указывающие только время, воздействуют только на временну́ю часть, но не на день.
Пример 4: Объединение нескольких единиц в одном вызове
Можно совмещать несколько относительных единиц в одной строке модификатора, разделяя их пробелами. Они применяются слева направо:
<?php
$date = new DateTime('2023-03-01');
$date->modify('+1 week +2 days');
echo $date->format('Y-m-d');Вывод:
2023-03-10Проблема переполнения месяца
Прибавление или вычитание месяцев не ограничивается концом более короткого месяца — происходит переполнение в следующий месяц. Посмотрите, что происходит при прибавлении одного месяца к 31 января:
<?php
$date = new DateTime('2023-01-31');
$date->modify('+1 month');
echo $date->format('Y-m-d');Вывод:
2023-03-03Поскольку в феврале 2023 года только 28 дней, «31 января + 1 месяц» приходится на несуществующее «31 февраля», которое PHP переводит на 3 марта. Если вам нужен последний день следующего месяца, используйте абсолютный относительный формат:
<?php
$date = new DateTime('2023-01-31');
$date->modify('last day of next month');
echo $date->format('Y-m-d');Вывод:
2023-02-28Избегайте случайной мутации с DateTimeImmutable
Поскольку modify() изменяет объект на месте, совместное использование одного DateTime в разных частях кода может привести к трудноуловимым ошибкам — изменение в одном месте затрагивает все ссылки на него. Если вы хотите, чтобы каждая операция возвращала новое значение, оставляя оригинал нетронутым, используйте DateTimeImmutable, чей метод modify() возвращает новый объект:
<?php
$original = new DateTimeImmutable('2023-03-01');
$nextWeek = $original->modify('+7 days');
echo $original->format('Y-m-d') . "\n"; // unchanged
echo $nextWeek->format('Y-m-d');Вывод:
2023-03-01
2023-03-08Полезные относительные форматы
modify() принимает разнообразную грамматику относительных выражений. Несколько распространённых примеров:
| Модификатор | Значение |
|---|---|
+5 days, -2 weeks | Прибавить или вычесть заданное количество единиц |
+1 year +6 months | Объединить несколько единиц в одной строке |
next monday, last friday | Перейти к указанному дню недели |
first day of this month | Перейти на 1-е число текущего месяца |
last day of next month | Перейти на последний день следующего месяца |
tomorrow, yesterday | Сдвинуть на один день (и сбросить время на полночь) |
14:30, midnight | Установить только временну́ю часть |
Связанные функции
date_add()— прибавитьDateIntervalк дате.date_sub()— вычестьDateIntervalиз даты.date_diff()— получить разницу между двумя датами.date_format()— форматировать объектDateTimeв строку.
Итоги
DateTime::modify() применяет строку в относительном формате к дате, изменяя объект на месте и возвращая его (или false при ошибке). Метод идеально подходит для арифметики дат и перехода к именованным дням, однако помните о двух вещах: арифметика месяцев переполняется за пределы коротких месяцев, а мутация является общей — используйте DateTimeImmutable, если вам нужно сохранить исходное значение.