Часовой пояс Битрикс путает разработчиков не потому, что настройка сложная, а потому что время в системе хранится сразу в трёх местах: серверные и административные настройки, date.timezone в PHP и time_zone в MySQL. На практике я разбирал такие ситуации обычно после переезда на новый сервер, восстановления базы из бэкапа или смены хостинга: заказы в интернет-магазине приходили с временем создания на 3-4 часа вперёд, агенты срабатывали не по расписанию, а в отчётах по продажам сутки считались неправильно. Разберу, где физически хранится время в Битриксе и как привести все три уровня к одному значению.
Три места, где в Битриксе живёт время
Прежде чем лезть в конфиги, разведём по местам три группы настроек, из которых в сумме складывается время на сайте: системные и административные настройки, часовой пояс PHP и часовой пояс MySQL.
Первая группа - это часы сервера плюс настройка часового пояса в панели управления Битриксом. Системные часы синхронизируются по NTP и дают базовый unix-timestamp: функция time() в PHP берёт значение именно оттуда, и никакая настройка часового пояса это число не меняет, она влияет только на то, как из timestamp собирается читаемая дата. Настройка в админке Битрикса добавляется поверх: она задаёт смещение, которое ядро применяет при выводе дат в интерфейсе и компонентах, независимо от того, в каком поясе физически стоит сервер.
Вторая группа - date.timezone в PHP. Он определяет часовой пояс по умолчанию для функций date(), strtotime(), DateTime и всего, что с ними связано, если Битрикс явно не переопределяет зону через собственный класс работы с часовыми поясами.
Третья группа - time_zone в MySQL. Она управляет тем, что возвращают NOW(), CURDATE(), CURRENT_TIMESTAMP и функция CONVERT_TZ(), а значит и тем, какое время реально попадает в поля вроде DATE_CREATE при вставке записи на стороне базы, а не PHP.
Пока все три группы согласованы, никто не задумывается о часовых поясах. Разъезжаются они обычно после смены хостинга, восстановления бэкапа на другом сервере или перехода на управляемую СУБД в облаке, где часовой пояс MySQL по умолчанию не совпадает с тем, что было на старом сервере.
| Группа настроек | Где посмотреть | На что влияет |
|---|---|---|
| Сервер и панель управления Битрикса | date, timedatectl status, раздел Настройки продукта | Базовый unix-timestamp и отображение дат в интерфейсе |
| date.timezone в PHP | phpinfo(), php - ini | date(), strtotime(), агенты, кастомные скрипты |
| time_zone в MySQL | SELECT @@global.time_zone | NOW(), CURDATE(), поля вроде DATE_CREATE при записи |
Настройка часового пояса в панели управления
В административной части Битрикса часовые пояса настраиваются на странице Настройки > Настройки продукта > Настройки модулей > Главный модуль, и сама поддержка включается там же отдельной опцией «Разрешить использование часовых поясов». Переопределяется пояс на уровне пользователя, а не сайта: посетитель может указать свой часовой пояс в профиле, и тогда система берёт значение из профиля. Рядом есть опция «По умолчанию автоматически определять часовой пояс по браузеру», она определяет пояс через Intl.DateTimeFormat и сохраняет его в cookies.
Технически Битрикс не переводит стрелки на сервере: время хранится в часовом поясе сервера, а после включения поддержки часовых поясов класс CTimeZone определяет отличие времени пользователя от времени сервера, и пользователь видит время с учётом своего локального пояса. Поэтому если после смены сервера время в интерфейсе резко съехало на несколько часов, в первую очередь стоит сверить именно эту настройку с реальным часовым поясом PHP, а не считать, что дело в самом Битриксе.
После изменения настройки обязательно сбросьте кэш: значение смещения кэшируется, и часть страниц ещё какое-то время может отдавать старое время из managed cache, пока кэш не протухнет сам или не будет очищен вручную.
date.timezone в PHP: почему крон живёт отдельной жизнью от сайта
Здесь чаще всего и находится основной источник путаницы. У PHP, как правило, не один php.ini, а минимум два: один используется веб-сервером или php-fpm пулом для показа сайта, второй - интерпретатором php-cli, который запускает крон. Это два разных файла на диске, и ничто не мешает им указывать разный часовой пояс.
Проверить активный часовой пояс в веб-окружении можно так:
<?php
echo date_default_timezone_get(), "\n";
echo date('Y-m-d H:i:s'), "\n";
Если сайт отдаёт правильное время, а агенты и крон-скрипты (например cron_events.php, который дёргает системный крон для выполнения агентов Битрикса) работают со сдвигом, разница почти всегда именно в CLI-версии php.ini. Проверьте её отдельно:
php --ini
и найдите файл, который используется именно консольным PHP, а не только тот, что подключён к Apache или php-fpm. Если нужно жёстко задать пояс, самый предсказуемый способ - прописать его в php.ini:
date.timezone = "Europe/Moscow"
и перезапустить php-fpm или веб-сервер, чтобы изменения подхватились. Ставить пояс через ini_set() внутри кастомных скриптов тоже можно, но тогда его придётся продублировать в каждом обработчике, который запускается в обход штатного ядра Битрикса: агенты, вебхуки, отдельные cli-скрипты для интеграций.
Бесплатный материал
🎁 Полезный скрипт в подарок
Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.
Без спама. Отписка в 1 клик.
time_zone в MySQL: где рождаются нестыковки в датах заказов
Часовой пояс на стороне PHP не имеет отношения к тому, что база данных пишет в поля с типом DATETIME при использовании функций NOW() или CURRENT_TIMESTAMP. Это отдельная настройка, системная переменная time_zone, и именно она отвечает за то, в каком поясе физически создаётся запись, когда вставка идёт через SQL-функцию, а не через PHP-строку с датой.
Проверить текущее значение:
SELECT @@global.time_zone, @@session.time_zone, NOW();
Если оба значения равны SYSTEM, MySQL берёт часовой пояс операционной системы, это нормальный вариант, если сами системные часы настроены верно. Проблема начинается, когда база переезжает на управляемый сервер в облаке или в контейнер, где по умолчанию стоит UTC, а старый сервер годами писал время по Москве. Внешне ничего не сломано, все запросы отрабатывают без ошибок, но дата создания заказа в базе оказывается на несколько часов раньше, чем показывает интерфейс, и это особенно заметно в интеграции с СДЭК: плановая дата передачи заказа в доставку считается от даты создания заказа, и смещение в MySQL напрямую влияет на то, какой день указывается получателю.
Задать нужный пояс можно на уровне сессии или глобально:
SET GLOBAL time_zone = '+03:00';
SET time_zone = '+03:00';
Числовое смещение вида +03:00 работает всегда, а именованные зоны вроде Europe/Moscow требуют, чтобы на сервере были загружены таблицы часовых поясов через утилиту mysql_tzinfo_to_sql, иначе CONVERT_TZ() и попытка задать зону по имени вернут NULL или ошибку. Для постоянного эффекта после перезагрузки сервера нужное значение стоит прописать в конфиге MySQL параметром default-time-zone, а не только через SET, который живёт до рестарта.
Как сбитое время проявляется на практике
Рассинхронизация редко бросается в глаза сразу, обычно её замечают через отчёты или жалобы клиентов. Вот с чем я сталкивался чаще всего:
- Заказы в интернет-магазине создаются с меткой времени, которая не совпадает с реальным моментом оформления, менеджеры путаются, кто оформил заказ первым, а автоматический расчёт даты доставки для СДЭК уезжает на день вперёд или назад.
- Отложенная публикация элементов инфоблока по полям ACTIVE_FROM и ACTIVE_TO срабатывает не в то время, которое было указано в редакторе, материал выходит раньше или позже, чем планировалось.
- Агенты Битрикса выполняются не по расписанию: часть проверок ориентируется на время, посчитанное PHP, и при расхождении с системными часами очередной запуск может либо не наступить вовремя, либо сработать почти сразу после предыдущего.
- Вебхуки во внешние системы, например в сценарии n8n, получают в теле события временную метку, которая не совпадает с фактическим временем действия на сайте, и если сценарий сравнивает разницу во времени между событиями, логика начинает давать сбои без единой ошибки в самом n8n.
- Отчёты по продажам и посещаемости считают границу суток не в полночь по местному времени, а со сдвигом, из-за чего цифры за «вчера» и «сегодня» не бьются с тем, что видно в CRM или в системе аналитики.
Ни один из этих симптомов не выглядит как проблема с часовым поясом на первый взгляд, обычно первым делом подозревают баг в модуле заказов или в конкретной интеграции, и на поиск настоящей причины уходит больше времени, чем на само исправление.
Пошаговая проверка и синхронизация всех уровней
Проверять стоит по порядку, от самого нижнего уровня к самому верхнему, иначе легко подправить настройку в админке поверх реально сломанных системных часов и получить два наложенных друг на друга сдвига.
- Системные часы сервера. В Linux смотрю через
dateиtimedatectl status, вторая команда сразу покажет, включена ли синхронизация NTP и активный часовой пояс ОС. - date.timezone для веб-окружения и отдельно для CLI, которым запускается крон, это разные php.ini, проверяю обе командой
php --iniв консоли и через phpinfo() на сайте. - Настройка часового пояса в админке Битрикса, сверяю с тем, что реально указано в php.ini, а не с тем, что должно быть по логике.
- Переменная time_zone в MySQL через
SELECT @@global.time_zone, NOW();, сравниваю результат NOW() с реальным временем на сервере. - После того как все уровни приведены к одному значению, перезапускаю php-fpm или веб-сервер, сбрасываю кэш Битрикса и проверяю создание тестового заказа и тестового элемента инфоблока с отложенной публикацией.
Если на проекте это разовая история и лезть в конфиги сервера самостоятельно нет времени, проще заказать разовую консультацию по настройке сервера: я гляну конфиги php.ini, my.cnf и настройки Битрикса и укажу, что именно рассинхронизировано, вместо того чтобы менять всё подряд наугад.
1С-Битрикс и PHP регулярно обновляются, поэтому перед внедрением я сверяюсь с актуальной документацией.
Частые вопросы
Почему после переезда на новый сервер время в заказах Битрикса стало отличаться от реального?
Чаще всего дело не в самом Битриксе, а в том, что на новом сервере другой часовой пояс операционной системы или другое значение time_zone в MySQL, чем было на старом. Панель управления просто продолжает применять прежнее смещение поверх уже изменившихся системных часов, поэтому итоговое время съезжает. Сверьте по очереди системные часы, php.ini и переменную time_zone в MySQL, обычно расхождение находится на одном из этих трёх уровней.
Нужно ли выставлять date.timezone в php.ini, если часовой пояс уже настроен в админке Битрикса?
Да. Настройка в админке задаёт только смещение, которое ядро Битрикса применяет при выводе дат, а date.timezone определяет часовой пояс по умолчанию для всех остальных функций PHP, в том числе для кастомных скриптов, вебхуков и агентов, которые не всегда проходят через полную инициализацию ядра.
Как узнать, какой time_zone установлен в MySQL, и поменять его без перезапуска сервера?
Выполните запрос SELECT @@global.time_zone, @@session.time_zone, NOW(), он покажет текущие значения и реальное время, которое база считает актуальным. Поменять на лету можно командой SET GLOBAL time_zone = ‘+03:00’, но после перезапуска MySQL это значение слетит, если не прописать default-time-zone в конфигурационном файле сервера.
Может ли неправильный часовой пояс сломать отложенную публикацию и работу агентов в Битриксе?
Да, и это один из самых незаметных симптомов. Отложенная публикация ориентируется на поля ACTIVE_FROM и ACTIVE_TO, а проверка агентов на время следующего запуска считается через PHP, поэтому расхождение между системными часами сервера и часовым поясом, который видит PHP, сдвигает и то, и другое. Материал может выйти на несколько часов раньше или позже плана, а агент сработать не по расписанию.