Время не ждет: почему в PHP с датами все сложно (и как это исправить)
Представьте: вы пишете блог, интернет-магазин или личный кабинет. И вдруг понимаете — нужно показать пользователю, когда была опубликована статья, сделан заказ или отправлено сообщение. Казалось бы, что может быть проще? Берешь функцию date() — и готово.
Но дьявол, как всегда, в деталях. В 2025 году разработчики на PHP по-прежнему совершают одни и те же ошибки: путают часовые пояса, забывают про неизменяемость объектов, используют устаревшие функции. А потом удивляются, почему на сайте время «прыгает», а тесты падают.
В этой статье мы разберем лучшие практики работы с датой и временем в PHP — от простых решений до профессиональных приемов. Вы узнаете, как получить текущую дату, как работать с часовыми поясами и как не выстрелить себе в ногу при работе с временными метками.
1. Самый простой способ: функция date()
Начнем с классики. Функция date() — это то, с чего начинают 90% новичков. Она принимает два параметра: формат вывода и (необязательно) timestamp. Если timestamp не указан, используется текущее время сервера.
echo date('Y-m-d H:i:s');
// Вывод: 2025-04-08 14:35:12
Вот самые популярные форматы:
Y— год (4 цифры)m— месяц (01–12)d— день месяца (01–31)H— часы в 24-часовом форматеi— минутыs— секунды
Проблема: date() зависит от настройки date.timezone в php.ini. Если вы не установили часовой пояс, PHP будет использовать системное время сервера. А сервер может находиться в другом часовом поясе — и тогда ваши пользователи увидят неверное время.
2. Профессиональный подход: класс DateTime
Начиная с PHP 5.2, у нас есть класс DateTime. Это объектно-ориентированный способ работы с датами, который гораздо гибче и безопаснее, чем функции date() и time().
$now = new DateTime();
echo $now->format('Y-m-d H:i:s');
// Вывод: 2025-04-08 14:35:12
Преимущества DateTime:
- Можно легко задать часовой пояс через конструктор
- Поддерживает модификацию даты (добавить дни, месяцы)
- Умеет сравнивать даты между собой
- Работает с интервалами
Пример с часовым поясом:
$now = new DateTime('now', new DateTimeZone('Europe/Moscow'));
echo $now->format('Y-m-d H:i:s');
// Вывод: 2025-04-08 17:35:12 (MSK, UTC+3)
2.1. DateTimeImmutable — ваш новый лучший друг
В PHP 5.5 появился DateTimeImmutable. Его главное отличие от обычного DateTime: он не изменяет сам себя. Вместо этого каждый метод (например, modify() или add()) возвращает новый объект.
$date = new DateTimeImmutable();
$modified = $date->modify('+1 day');
echo $date->format('Y-m-d'); // 2025-04-08 (не изменилось!)
echo $modified->format('Y-m-d'); // 2025-04-09 (новый объект)
Почему это важно? Потому что обычный DateTime — это объект-ссылка. Если вы передадите его в функцию и там измените, оригинал тоже изменится. С Immutable такой проблемы нет. В 2025 году это считается стандартом де-факто для серьезных проектов.
3. Как получить timestamp: time() vs DateTime
Иногда вам нужна не дата, а Unix timestamp — количество секунд с 1 января 1970 года. PHP предлагает два пути:
// Старый способ
echo time(); // 1744112112
// Новый способ
echo (new DateTime())->getTimestamp(); // 1744112112
Для простых задач time() вполне подходит. Но если вы работаете с часовыми поясами или сложными расчетами — используйте DateTime::getTimestamp().
4. Работа с часовыми поясами: как не облажаться
Это самая частая ошибка. Разработчик пишет echo date('Y-m-d'); и получает время сервера, которое может отличаться от времени пользователя на 3, 5 или 11 часов.
Правило №1: Всегда храните даты в UTC. Это международный стандарт. Преобразуйте в локальный часовой пояс только при выводе пользователю.
// Сохраняем в UTC
$utc = new DateTime('now', new DateTimeZone('UTC'));
echo $utc->format('Y-m-d H:i:s'); // 2025-04-08 11:35:12 UTC
// При выводе конвертируем
$userTimezone = new DateTimeZone('America/New_York');
$userDate = $utc->setTimezone($userTimezone);
echo $userDate->format('Y-m-d H:i:s'); // 2025-04-08 07:35:12 EDT
Правило №2: Список поддерживаемых часовых поясов в PHP огромен. Используйте DateTimeZone::listIdentifiers(), чтобы получить полный перечень.
$timezones = DateTimeZone::listIdentifiers();
print_r($timezones);
// ['Africa/Abidjan', 'Africa/Accra', ... , 'Pacific/Wallis']
5. Форматирование даты для пользователя
Форматы вроде 2025-04-08 14:35:12 хороши для базы данных, но ужасны для пользователя. В 2025 году принято показывать даты в человекочитаемом виде:
- «Сегодня в 14:35»
- «Вчера в 09:15»
- «8 апреля 2025 года»
Вот пример функции, которая делает дату «дружественной»:
function friendlyDate(DateTimeImmutable $date): string {
$now = new DateTimeImmutable();
$diff = $now->diff($date);
if ($diff->days === 0) {
return 'Сегодня в ' . $date->format('H:i');
} elseif ($diff->days === 1) {
return 'Вчера в ' . $date->format('H:i');
} elseif ($diff->days < 7) {
return $diff->days . ' дня назад';
} else {
return $date->format('j F Y года');
}
}
echo friendlyDate(new DateTimeImmutable('2025-04-07 10:00:00'));
// Вывод: Вчера в 10:00