Временные зоны в PHP: как не сойти с ума и подружиться с UTC

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему время — это боль

Представьте: вы пишете интернет-магазин. Клиент из Нью-Йорка оформляет заказ в 15:00 по местному времени. Вы сохраняете дату в базу. А потом сервер, стоящий в Москве, решает, что заказ сделан в 22:00. И начинается хаос: доставка опаздывает, отчеты не сходятся, клиенты злятся.

Знакомая ситуация? Добро пожаловать в мир временных зон в PHP. Эта тема — настоящий квест для новичков и даже для опытных разработчиков. Но есть хорошая новость: если один раз разобраться и настроить всё правильно, вы забудете о головной боли с датами навсегда.

В этой статье мы разберем, как работать с часовыми поясами в PHP, как избежать ловушек с летним временем и почему UTC — ваш лучший друг. Поехали!

Глобальная настройка временной зоны в PHP

Самый первый шаг — убедиться, что PHP знает, в каком часовом поясе работает ваш сервер. Делается это через директиву date.timezone в php.ini либо прямо в коде с помощью функции date_default_timezone_set().

// Устанавливаем временную зону для всего скрипта
date_default_timezone_set('Europe/Moscow');

echo date('Y-m-d H:i:s'); // Выведет текущее время по Москве

Но внимание! Если вы работаете с пользователями из разных стран, фиксировать одну зону на весь проект — плохая идея. Лучше всегда хранить время в UTC (всемирное координированное время) и конвертировать его под конкретного пользователя.

Проверка текущей временной зоны

Всегда полезно знать, какая зона установлена прямо сейчас:

echo date_default_timezone_get(); // Например: 'Europe/Moscow'

Объект DateTimeZone — ваш главный инструмент

В PHP есть мощный объект DateTimeZone. Он позволяет работать с часовыми поясами как с самостоятельными сущностями. Давайте посмотрим на базовый пример:

$timezone = new DateTimeZone('America/New_York');
$datetime = new DateTime('now', $timezone);

echo $datetime->format('Y-m-d H:i:s'); // Время в Нью-Йорке сейчас

Обратите внимание: мы передали временную зону прямо в конструктор DateTime. Это самый чистый способ работы с часовыми поясами в PHP.

Список всех доступных временных зон

Хотите узнать, какие зоны вообще поддерживает PHP? Вызовите метод listIdentifiers():

$zones = DateTimeZone::listIdentifiers();
echo count($zones); // Около 400+ зон!

// Вывести первые 10
print_r(array_slice($zones, 0, 10));

Этот список огромен. Но вам не нужно запоминать все — достаточно знать стандартные идентификаторы типа Europe/London, Asia/Tokyo или UTC.

Конвертация между временными зонами

Самая частая задача: взять время в одной зоне и перевести в другую. В PHP это делается элегантно через метод setTimezone().

// Время по UTC
$utcTime = new DateTime('2025-03-15 12:00:00', new DateTimeZone('UTC'));

// Конвертируем в Токио
$tokyoTime = clone $utcTime;
$tokyoTime->setTimezone(new DateTimeZone('Asia/Tokyo'));

echo $utcTime->format('Y-m-d H:i:s') . ' UTC'; // 2025-03-15 12:00:00 UTC
echo ' = ';
echo $tokyoTime->format('Y-m-d H:i:s') . ' Tokyo'; // 2025-03-15 21:00:00 Tokyo

Обратите внимание: мы использовали clone, чтобы не изменить исходный объект. Если этого не сделать, оригинальное время тоже "переедет" в Токио.

Лучшая практика: хранить всё в UTC

Золотое правило веб-разработки: всегда храните даты и время в UTC. База данных, кэш, логи — везде UTC. А конвертацию под пользователя делайте только на этапе вывода.

// Сохраняем в БД (примерно)
$nowUTC = new DateTime('now', new DateTimeZone('UTC'));
$db->query("INSERT INTO orders (created_at) VALUES ('{$nowUTC->format('Y-m-d H:i:s')}')");

// При выводе для пользователя из Лос-Анджелеса
$userTimezone = new DateTimeZone('America/Los_Angeles');
$localTime = $nowUTC->setTimezone($userTimezone);
echo $localTime->format('Y-m-d H:i:s');

Летнее время (DST): как с ним бороться

Ах, это летнее время! Каждый год весной мы "теряем" час, а осенью — "находим". PHP умеет корректно обрабатывать DST, но есть подводные камни.

Например, в США переход на летнее время происходит в марте. Часа с 2:00 до 3:00 просто не существует. Если вы попытаетесь создать DateTime для этого промежутка, PHP может "сдвинуть" время на корректное значение.

// В США 14 марта 2025 года в 2:00 ночи часы перевели на 3:00
$date = new DateTime('2025-03-14 02:30:00', new DateTimeZone('America/New_York'));
echo $date->format('Y-m-d H:i:s'); // Выведет 2025-03-14 03:30:00 — PHP сам подправил!

Это поведение может быть как полезным, так и опасным. Если вам нужно точное "сырое" время, работайте с Unix timestamp — он не зависит от временных зон и DST.

$timestamp = time(); // Текущий Unix timestamp (всегда UTC)
$date = new DateTime("@$timestamp"); // Создаем из timestamp
echo $date->format('Y-m-d H:i:s'); // Время по UTC

Смещение временной зоны относительно UTC

Иногда нужно узнать, на сколько часов конкретная зона отличается от UTC. Для этого используйте метод getOffset():

$timezone = new DateTimeZone('Asia/Vladivostok');
$offset = $timezone->getOffset(new DateTime('now', new DateTimeZone('UTC')));

echo $offset / 3600; // 10 часов (UTC+10)

Это особенно полезно, когда вы строите интерфейс выбора часового пояса для пользователя — можно показать не только название, но и смещение.

Получение названия временной зоны из смещения

Обратная задача: у вас есть смещение (например, +5:30), и нужно найти подходящую зону. Это сложнее, потому что одно смещение может соответствовать нескольким зонам. Но можно перебрать:

function findTimeZoneByOffset($offsetHours) {
    $zones = DateTimeZone::listIdentifiers();
    foreach ($zones as $zone) {
        $tz = new DateTimeZone($zone);
        $offset = $tz->getOffset(new DateTime('now', new                

Блоги

Рекомендаций по книгам