Дата сохранилась не та - разбор причин
Дата уехала на несколько часов, не разобралась или попала не в тот период выборки. Разбираем причины по убыванию частоты.
С чего начать
Смотрим, включены ли часовые пояса и какой пояс у пользователя:
use Bitrix\Main\Type\DateTime;
$dt = new DateTime();printf("пользователю=%s серверное=%s\n", $dt->toString(), (clone $dt)->disableUserTime());// расхождение означает, что пояса включены и перевод времени работает// в базе дата лежит в серверном поясе независимо от выводаРазница между двумя строками объясняет большую часть жалоб «время не то». Платформа переводит время в пояс пользователя при выводе, а в базе хранит его в серверном поясе.
Разбираем пользовательский ввод правильно:
$dt = DateTime::tryParse($request->get('date'), 'DD.MM.YYYY HH:MI:SS');if ($dt === null) { $errors[] = 'Дата введена в неизвестном формате';}$server = DateTime::createFromUserTime('25.11.2025 18:00'); // ввод в поясе пользователя// конструктор при неразобранном формате бросает исключение, а разбор возвращает nullРазбор строки и создание объекта ведут себя по-разному при неверном формате. Пользовательский ввод разбирают безопасным способом, а перевод в серверный пояс делают отдельным вызовом.
Проверяем границы периода в фильтре:
$rows = ElementTable::getList([ 'filter' => [ '>=DATE_CREATE' => new DateTime('01.11.2025 00:00:00', 'd.m.Y H:i:s'), '<DATE_CREATE' => new DateTime('01.12.2025 00:00:00', 'd.m.Y H:i:s'), ],])->fetchAll();// верхнюю границу берут строгой: иначе в выборку попадает лишний деньПериод задают полуоткрытым интервалом. Нестрогая верхняя граница с началом суток захватывает записи следующего дня, а с концом суток теряет записи последних секунд.
Причины
-
Время переводится в пояс пользователя примерно 30% случаев
ПризнакВ интерфейсе одно время, в журнале и в базе другое, разница ровно в несколько часов.
ПроверкаСравниваем вывод с переводом в пояс пользователя и без него.
Что делатьДля журналов и служебных записей перевод отключают: там нужно именно серверное время.
-
Пользовательский ввод разобран неверно примерно 25% случаев
ПризнакДата сохраняется пустой или страница падает с ошибкой при вводе в другом формате.
ПроверкаСмотрим, чем разбирается строка и указан ли ожидаемый формат.
Что делатьРазбираем ввод безопасным методом с проверкой результата, а не конструктором объекта.
-
Границы периода заданы неточно примерно 20% случаев
ПризнакВ отчёт попадают записи соседнего дня или теряются записи последнего дня.
ПроверкаСмотрим операторы сравнения у обеих границ периода и время в них.
Что делатьБерём полуоткрытый интервал: нижняя граница нестрогая, верхняя строгая.
-
Дата хранится строкой в своём формате примерно 15% случаев
ПризнакСортировка по дате идёт как по тексту, фильтр по периоду не работает.
ПроверкаСмотрим тип поля в таблице и то, что в него пишется.
Что делатьХраним дату полем даты: строковое поле не умеет ни сравниваться, ни сортироваться правильно.
-
Время потерялось при переводе в дату примерно 10% случаев
ПризнакУ записи полночь вместо реального времени события.
ПроверкаСмотрим, каким типом создаётся значение: только дата или дата со временем.
Что делатьБерём тип с временем там, где время важно: тип даты нормализует время к началу суток.
Частые вопросы
Почему в журнале время отличается от интерфейса?
При включённых часовых поясах вывод переводится в пояс пользователя, а в журнал попадает то, что напечатали. Для служебных записей перевод отключают явно.
Как безопасно разобрать дату из формы?
Методом разбора с указанием ожидаемого формата и проверкой на пустой результат. Конструктор при неизвестном формате бросает исключение и роняет страницу.
Как правильно задать период в фильтре?
Полуоткрытым интервалом: от начала первого дня включительно до начала следующего дня строго. Так не теряются записи последних секунд суток.
Почему у даты без времени появилось 18:00?
Разбор текста без времени подставляет время окончания рабочего дня из настроек календаря. Если время важно, его задают явно.
Что хранить в базе: дату или дату со временем?
То, что нужно бизнесу: срок действия - датой, факт события - датой со временем. Тип даты нормализует время к нулю и незаметно теряет часы.
Смежное
- Даты и время - оглавление подтемы
- Даты в коде: объект, часовой пояс, фильтр по периоду - как работать с датами правильно
- Выборка ORM возвращает не то: разбор причин - соседний разбор выборок
- Свой журнал решения: файл, ротация, что писать - время в записях журнала
- Отчёты по заказам: агрегаты, группировка, выгрузка - периоды в отчётах
- Ядро D7 - устройство ядра целиком
- Дата и время изнутри: хранение, пояса, форматы - устройство преобразований за этими причинами