Как вычислить разницу между двумя датами в PHP: от новичка до профи
Вы когда-нибудь задавались вопросом: «Сколько дней прошло с моего последнего отпуска?» или «Через сколько часов закончится акция на сайте?»? Если вы PHP-разработчик, то эти вопросы превращаются в одну задачу: как вычислить разницу между двумя датами.
Этот вопрос — один из самых популярных на Stack Overflow с тысячами просмотров. И неспроста: работа с датами в PHP может быть коварной. Високосные годы, часовые пояса, разные форматы — всё это способно сломать даже самый продуманный код.
В этой статье мы разберём 5 проверенных способов вычисления разницы между датами в PHP — от простейших до профессиональных. Вы узнаете, когда какой метод использовать, и получите готовые примеры кода.
1. Классический метод: strtotime() и простая арифметика
Самый старый и интуитивно понятный способ — перевести даты в Unix-метки (timestamp) с помощью функции strtotime() и просто вычесть одно число из другого.
<?php
$date1 = strtotime('2024-01-15');
$date2 = strtotime('2024-03-20');
$diff_seconds = $date2 - $date1;
$diff_days = floor($diff_seconds / (60 * 60 * 24));
echo "Разница в днях: " . $diff_days; // Выведет: 65
?>
Плюсы: простота, работает в любой версии PHP.
Минусы: не учитывает часовые пояса, проблемы с датами до 1970 года, нет встроенной поддержки месяцев и лет (ведь их длина варьируется).
Этот метод подходит для быстрых расчётов «на коленке», но для серьёзных проектов лучше использовать более современные инструменты.
2. Современный стандарт: класс DateTime и метод diff()
Начиная с PHP 5.2, у нас есть мощный класс DateTime. Это настоящий швейцарский нож для работы с датами. Метод diff() возвращает объект DateInterval, который содержит всю информацию о разнице.
<?php
$date1 = new DateTime('2024-01-15');
$date2 = new DateTime('2024-03-20');
$interval = $date1->diff($date2);
echo "Разница: " . $interval->days . " дней"; // 65
echo "или " . $interval->m . " месяцев и " . $interval->d . " дней"; // 2 месяца и 5 дней
?>
DateInterval даёт доступ к таким свойствам:
y— годыm— месяцыd— дниh— часыi— минутыs— секундыdays— общее количество дней (самое полезное!)invert— флаг: 0 если первая дата раньше, 1 если позже
Этот метод учитывает високосные годы и корректно работает с разными календарными особенностями. Именно его рекомендуют в официальной документации PHP.
3. Форматирование разницы: как вывести «2 года 3 месяца 10 дней»
Часто нужно не просто получить число, а красиво отформатировать разницу для пользователя. Метод format() объекта DateInterval приходит на помощь.
<?php
$birthday = new DateTime('1990-05-15');
$today = new DateTime();
$age = $birthday->diff($today);
echo $age->format('%y лет %m месяцев %d дней');
// Пример: 34 лет 2 месяцев 3 дней
?>
Спецификаторы формата:
%y— годы%m— месяцы%d— дни%h— часы%i— минуты%s— секунды%a— общее количество дней (альтернативаdays)%r— знак "минус" если разница отрицательная
Хотите склонение слов «день/дня/дней»? Придётся написать свою логику — PHP не умеет склонять существительные. Но это отличное упражнение!
4. Работа с часовыми поясами: когда время имеет значение
Если ваше приложение работает с пользователями из разных часовых поясов, игнорировать временные зоны нельзя. Одна и та же метка времени может означать разное время в Москве и Нью-Йорке.
<?php
$timezone_moscow = new DateTimeZone('Europe/Moscow');
$timezone_ny = new DateTimeZone('America/New_York');
$date_moscow = new DateTime('2024-03-20 15:00:00', $timezone_moscow);
$date_ny = new DateTime('2024-03-20 08:00:00', $timezone_ny);
// Обе даты — одно и то же мгновение!
$interval = $date_moscow->diff($date_ny);
echo "Разница: " . $interval->h . " часов"; // Выведет: 0 часов
?>
Совет: всегда храните даты в UTC в базе данных, а конвертацию в локальный часовой пояс делайте только при отображении пользователю. Это спасёт вас от множества головных болей.
5. Профессиональный уровень: библиотека Carbon
Если вы пишете на Laravel или Symfony, вы наверняка уже встречали Carbon — расширение класса DateTime с невероятно удобным API. Это стандарт де-факто в современном PHP.
Установка через Composer:
composer require nesbot/carbon
А теперь — магия:
<?php
use Carbon\Carbon;
$date1 = Carbon::parse('2024-01-15');
$date2 = Carbon::parse('2024-03-20');
// Разница в днях
echo $date1->diffInDays($date2); // 65
// Разница в часах
echo $date1->diffInHours($date2); // 1560
// Человекочитаемый формат
echo $date1->diffForHumans($date2); // "2 months before"
echo $date2->diffForHumans($date1); // "2 months from now"
// Сравнение
if ($date1->isPast()) {
echo "Дата в прошлом";
}
if ($date2->isFuture()) {
echo "Дата в будущем";
}
?>
Carbon предлагает десятки методов: addDays(), subMonths(), startOfDay(), endOfWeek() и многие другие