Как вычислить разницу между двумя датами в PHP: полное руководство с примерами
Вы когда-нибудь сталкивались с задачей: «сколько дней прошло с момента регистрации пользователя?», «какой возраст человека по дате рождения?» или «через сколько часов заканчивается акция?»? Если да, то вы точно задавались вопросом: как вычислить разницу между двумя датами в PHP? Это один из самых популярных вопросов на Stack Overflow, и не зря: работа с датами — базовая, но коварная тема.
В этой статье мы разберем три основных подхода: классический strtotime(), современный объектно-ориентированный DateTime и мощный сторонний пакет Carbon. Вы узнаете не только «как сделать», но и какой способ выбрать под вашу задачу. Поехали!
Почему простое вычитание дат — это плохая идея?
Начинающие разработчики часто пытаются сделать так:
<?php
$date1 = '2024-01-15';
$date2 = '2024-01-10';
$diff = $date2 - $date1; // Ошибка! Строки нельзя вычитать
?>
PHP не умеет вычитать строки, даже если они похожи на даты. Результат будет 0 или предупреждение. Даже если вы используете strtotime() и получите Unix-метки, простое вычитание секунд даст вам лишь количество секунд, а не удобный формат «2 дня 3 часа 15 минут». Для этого нужны специальные инструменты.
Подход 1: Классика — strtotime() и ручные расчёты
Этот метод знаком всем, кто начинал с PHP 4 или 5. Функция strtotime() преобразует текстовое представление даты в Unix-метку (количество секунд с 1 января 1970 года). Затем мы вычитаем метки и делим на количество секунд в дне.
Пример: разница в днях
<?php
$date1 = strtotime('2024-12-25');
$date2 = strtotime('2024-12-20');
$seconds_diff = $date1 - $date2;
$days_diff = floor($seconds_diff / (60 * 60 * 24));
echo "Разница: $days_diff дней"; // Выведет: Разница: 5 дней
?>
Плюсы: простота, не требует объектов, работает быстро.
Минусы:
- Нет поддержки часовых поясов (всегда UTC).
- При переводе на летнее/зимнее время возможна ошибка в 1 час (а значит и в 1 день, если граница перехода попадает на ваш интервал).
- Чтобы получить разницу в месяцах или годах, нужно писать сложную логику с учётом високосных годов.
Когда использовать: только для грубых расчётов (например, «прошло больше 30 дней?») или если у вас древняя кодовая база.
Подход 2: DateTime и DateInterval — современный PHP-стандарт
Начиная с PHP 5.2, в языке появился мощный класс DateTime. В паре с DateInterval он решает 95% задач по работе с датами. Это рекомендованный способ вычисления разницы между двумя датами в PHP.
Базовый пример: разница в днях, месяцах и годах
<?php
$date1 = new DateTime('2024-01-15');
$date2 = new DateTime('2023-11-10');
$interval = $date1->diff($date2);
echo $interval->format('%y лет, %m месяцев, %d дней');
// Выведет: 0 лет, 2 месяцев, 5 дней
?>
Магия в том, что diff() сам учитывает високосные годы, разное количество дней в месяцах и даже часовые пояса (если они заданы).
Получаем доступ к отдельным компонентам
<?php
$date1 = new DateTime('2024-12-25');
$date2 = new DateTime('2024-01-01');
$interval = $date1->diff($date2);
echo "Лет: " . $interval->y . "<br>";
echo "Месяцев: " . $interval->m . "<br>";
echo "Дней: " . $interval->d . "<br>";
echo "Всего дней (total): " . $interval->days . "<br>";
// Выведет:
// Лет: 0
// Месяцев: 11
// Дней: 24
// Всего дней (total): 359
?>
Обратите внимание на свойство days — это общее количество дней в интервале (в отличие от d, которое показывает только остаток дней внутри месяца). Это очень удобно, когда нужно сказать «прошло 359 дней».
Работа с временем: часы, минуты, секунды
<?php
$start = new DateTime('2024-01-01 08:30:00');
$end = new DateTime('2024-01-01 14:45:30');
$interval = $start->diff($end);
echo $interval->format('%h часов, %i минут, %s секунд');
// Выведет: 6 часов, 15 минут, 30 секунд
?>
Плюсы:
- Учёт часовых поясов (задаётся вторым параметром в конструкторе).
- Умный расчёт месяцев и лет.
- Встроенное форматирование через format().
- Код читаемый и поддерживаемый.
Минусы: нужно привыкнуть к ООП-синтаксису.
Подход 3: Carbon — «швейцарский нож» для дат
Если вы работаете с Laravel или Symfony, вы уже встречали Carbon. Это расширение класса DateTime, которое добавляет сотни методов-помощников. Carbon делает код элегантным и сокращает количество строк в 2-3 раза.
Установка через Composer
composer require nesbot/carbon
Пример: разница «на человеческом языке»
<?php
use Carbon\Carbon;
$date1 = Carbon::parse('2024-12-25');
$date2 = Carbon::parse('2024-01-01');
// Получаем объект CarbonInterval
$diff = $date1->diff($date2);
echo $diff->forHumans(); // Выведет: 11 месяцев 3 недели после
// или на русском (если установлен локализованный пакет): 11 месяцев 3 недели назад
?>
Метод forHumans() — это киллер-фича. Он сам подбирает формат: «3 часа назад», «2 дня после», «через 5 минут».
Сравнение с текущим моментом
<?php
$past = Carbon::now()->subDays(10);
echo $past->diffForHumans(); // "10 дней назад"
$future = Carbon::now()->addHours(5);
echo $future->diffForHumans(); // "через 5 часов"
?>
Проверка: «прошло ли больше N дней?»
<?php
$registrationDate = Carbon::parse('2023-06-01