1С Битрикс · 8 мин чтения

Часовой пояс Битрикс: сбилось время в PHP, MySQL и настройках

Часовой пояс Битрикс путает разработчиков не потому, что настройка сложная, а потому что время в системе хранится сразу в трёх местах: серверные и административные настройки, 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 или в системе аналитики.

Ни один из этих симптомов не выглядит как проблема с часовым поясом на первый взгляд, обычно первым делом подозревают баг в модуле заказов или в конкретной интеграции, и на поиск настоящей причины уходит больше времени, чем на само исправление.

Пошаговая проверка и синхронизация всех уровней

Проверять стоит по порядку, от самого нижнего уровня к самому верхнему, иначе легко подправить настройку в админке поверх реально сломанных системных часов и получить два наложенных друг на друга сдвига.

  1. Системные часы сервера. В Linux смотрю через date и timedatectl status, вторая команда сразу покажет, включена ли синхронизация NTP и активный часовой пояс ОС.
  2. date.timezone для веб-окружения и отдельно для CLI, которым запускается крон, это разные php.ini, проверяю обе командой php --ini в консоли и через phpinfo() на сайте.
  3. Настройка часового пояса в админке Битрикса, сверяю с тем, что реально указано в php.ini, а не с тем, что должно быть по логике.
  4. Переменная time_zone в MySQL через SELECT @@global.time_zone, NOW();, сравниваю результат NOW() с реальным временем на сервере.
  5. После того как все уровни приведены к одному значению, перезапускаю 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, сдвигает и то, и другое. Материал может выйти на несколько часов раньше или позже плана, а агент сработать не по расписанию.

Есть задача?

Обсудим в мессенджере

Расскажите, что нужно сделать — отвечу в течение 4 часов в рабочее время. Первая консультация бесплатно.

Продолжая пользование настоящим сайтом Вы выражаете своё согласие на обработку Ваших персональных данных (файлов куки) с использованием Yandex.Metrika.
Понятно