Работа с временными метками в информационной системе 1С:Предприятие часто становится камнем преткновения даже для опытных разработчиков. Казалось бы, простая задача — проверить, совпадают ли две даты — превращается в головоломку из-за наличия компонента времени. В базе данных любая дата хранится с точностью до секунды, а иногда и миллисекунды, что делает прямое сравнение оператором = ненадежным, если нас интересует только календарный день.

Представьте ситуацию: одна дата получена из журнала регистрации в 09:00:00, а вторая сформирована программно как начало дня (00:00:00). При прямом сравнении система вернет Ложь, хотя визуально для пользователя это один и тот же день. Разработчик должен четко понимать разницу между типом Дата и её представлением, чтобы избежать логических ошибок в отчетах и документах.

В этой статье мы детально разберем, как корректно сравнивать дни дат, игнорируя время. Мы рассмотрим встроенные функции платформы, особенности работы с NULL-значениями и нюансы производительности при выборке больших объемов данных.

Проблема времени в типе Дата

Тип данных Дата в 1С является составным и включает в себя календарную дату и время суток. Когда вы получаете значение из поля документа или переменной, оно почти всегда содержит время. Если вы попытаетесь сравнить две такие даты напрямую, система будет учитывать каждую секунду.

Например, если переменная ДатаДокумента равна 25.10.2023 14:30:00, а переменная ДатаОтчета равна 25.10.2023 00:00:00, выражение ДатаДокумента = ДатаОтчета вернет ложь. Это частая ошибка при написании условий отбора в запросах или фильтрах форм.

Чтобы решить эту проблему, необходимо привести обе даты к единому знаменателю — началу суток. В платформе 1С для этого существует специальная функция, которая отсекает время, оставляя только дату.

⚠️ Внимание: Никогда не полагайтесь на визуальное отображение даты в отладчике. Отладчик может скрывать время по умолчанию, но при сравнении оно учитывается всегда.

Использование функции НачалоДня() является стандартом де-факто для таких операций. Она возвращает новую дату, у которой время установлено в 00:00:00. Применяя эту функцию к обеим сравниваемым величинам, вы гарантируете корректность проверки.

Использование функции НачалоДня

Функция НачалоДня(Дата) принимает значение типа Дата и возвращает дату начала этого дня. Это наиболее производительный и читаемый способ сравнения дней. Синтаксис функции предельно прост и не требует дополнительных библиотек.

Рассмотрим пример кода на встроенном языке 1С, где мы проверяем, попадает ли дата документа в текущий день:

Если НачалоДня(ДатаДокумента) = НачалоДня(ТекущаяДата()) Тогда

Сообщить("Документ создан сегодня");

КонецЕсли;

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

💡

Используйте НачалоДня() не только для сравнения, но и для группировки данных в запросах, чтобы объединить записи одного дня независимо от времени их создания.

Существует также функция КонецДня(), которая возвращает время 23:59:59.999. Её использование для сравнения дней менее удобно, так как требует дополнительных вычислений для нормализации, но может пригодиться в специфических задачах фильтрации диапазонов.

Сравнение через форматирование и строки

Иногда разработчики прибегают к преобразованию даты в строку для сравнения. Этот метод использует функцию Формат() или неявное приведение типов. Хотя такой подход работает, он считается менее оптимальным с точки зрения производительности.

При преобразовании даты в строку вида "ДФ=dd.MM.yyyy" вы теряете типизацию. Сравнение строк происходит посимвольно, что медленнее, чем сравнение числовых представлений дат внутри движка 1С. Кроме того, такой код становится зависимым от локали пользователя.

Пример неправильного подхода:

Если Формат(Дата1, "ДФ=dd.MM.yyyy") = Формат(Дата2, "ДФ=dd.MM.yyyy") Тогда

// Логика сравнения

КонецЕсли;

Использование строк оправдано только в случаях, когда дата приходит из внешнего источника в текстовом формате и её парсинг затруднен. В остальных случаях следует придерживаться работы с типом Дата.

Почему строки медленнее?

Операции со строками требуют выделения памяти под новый объект строки, копирования данных и посимвольного сравнения. Операции с датами выполняются как сравнение целых чисел (ticks).

Еще один риск строкового сравнения — зависимость от региональных настроек. Если на компьютере пользователя изменится формат краткой даты, логика сравнения может нарушиться, если не задан жесткий формат в функции.

Особенности работы в запросах

При написании запросов к базе данных 1С сравнение дней имеет свои нюансы. В языке запросов 1С также доступна функция НАЧАЛОДНЯ(). Использование её в условии ГДЕ позволяет эффективно использовать индексы, если структура запроса построена правильно.

Однако стоит избегать применения функций к полям таблиц в условии соединения или отбора, если это возможно, так как это может привести к полному сканированию таблицы вместо использования индекса. В случае сравнения дней это часто неизбежно, но можно оптимизировать запрос.

Вместо сравнения дней через функцию можно использовать диапазон дат. Это наиболее быстрый способ для больших выборок:

ВЫБРАТЬ

Документ.Ссылка,

Документ.Дата

ИЗ

Документ.ЗаказПокупателя КАК Документ

ГДЕ

Документ.Дата >= &НачалоДня

И Документ.Дата < &КонецДня

Здесь параметры &НачалоДня и &КонецДня вычисляются в коде перед выполнением запроса. Такой подход позволяет СУБД эффективно использовать индекс по полю Дата.

Метод Производительность Читаемость Рекомендация
Прямое сравнение Высокая Низкая (ошибки) Только если время гарантированно совпадает
НачалоДня() Средняя Высокая Стандарт для бизнес-логики
Диапазон в запросе Очень высокая Средняя Лучший выбор для отчетов
📊 Какой метод сравнения дат вы используете чаще всего?
Прямое сравнение =
НачалоДня()
Формат в строку
Диапазон дат в запросе

Обработка неопределенных значений

Одной из частых причин ошибок выполнения является попытка вызвать функцию НачалоДня() для пустого значения (NULL или Неопределено). В 1С пустая дата не равна дате начала эпохи, это отдельное состояние отсутствия значения.

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

Правильный паттерн проверки выглядит следующим образом:

  • 🛑 Сначала проверяем Не ПустаяДата(Дата1) и Не ПустаяДата(Дата2).
  • ✅ Только если обе даты заполнены, выполняем сравнение через НачалоДня.
  • ⚠️ Если одна из дат пуста, решение зависит от бизнес-логики (считать равными или разными).

Функция ПустаяДата() возвращает специальное значение, которое не имеет компонента времени. Сравнивать его с обычной датой бессмысленно без предварительной обработки.

⚠️ Внимание: В запросах пустые даты обрабатываются автоматически как NULL. Убедитесь, что в параметрах запроса тип значения допускает пустую дату, иначе возникнет ошибка приведения типов.

Сравнение интервалов и сдвиги

Часто требуется сравнить не просто равенство дней, а попадание даты в интервал или сдвиг на определенное количество дней. Для этого используются функции ДобавитьМесяц(), ДобавитьКДате() в связке с нормализацией.

При сдвиге даты важно помнить о переходе через границы месяцев и лет. Функции работы с датой в 1С автоматически учитывают високосные годы и разное количество дней в месяцах, что упрощает разработку.

Пример проверки, что дата не старше 30 дней (с учетом времени):

МинимальнаяДата = ДобавитьКДате(ТекущаяДата(), "Д", -30);

Если ДатаДокумента > МинимальнаяДата Тогда

// Документ свежий

КонецЕсли;

Если же нужно проверить именно дни (например, штраф начисляется за каждый просроченный календарный день), то обе даты нужно нормализовать функцией НачалоДня перед вычитанием.

☑️ Алгоритм безопасного сравнения

Выполнено: 0 / 5

Частые ошибки и антипаттерны

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

Другая распространенная ошибка — сравнение строковых представлений дат без учета формата. Если в одной части системы дата хранится как DD.MM.YYYY, а в другой как YYYY-MM-DD, прямое сравнение строк даст неверный результат.

Также стоит избегать сравнения дат с использованием разницы в секундах и деления на количество секунд в сутках (86400). Из-за високосных секунд или особенностей хранения времени в СУБД такой расчет может давать погрешность в 1 день.

Используйте встроенные средства платформы, они протестированы и оптимизированы разработчиками фирмы . Самописные функции конвертации времени часто работают медленнее и содержат баги.

💡

Золотое правило: Всегда нормализуйте даты функцией НачалоДня() перед сравнением, если время суток не имеет значения для вашей задачи.

Можно ли сравнивать даты без функции НачалоДня?

Технически можно, если вы гарантируете, что время в обеих датах одинаково (например, обе записаны как 00:00:00). Но на практике это ненадежно, так как время может измениться при импорте данных или сохранении в журнал регистрации.

Влияет ли часовой пояс на сравнение дат в 1С?

Внутри базы 1С даты хранятся в формате UTC или локальном времени сервера в зависимости от конфигурации. При сравнении внутри одной базы часовой пояс не влияет, если обе даты взяты из одного источника. Проблемы возникают при обмене с внешними системами.

Что быстрее: НачалоДня или форматирование в строку?

Функция НачалоДня значительно быстрее. Она работает с числовым представлением даты. Форматирование в строку требует выделения памяти, преобразования чисел в символы и сравнения массивов байт, что ресурсоемко.

Как сравнить даты в СКД (Системе Компоновки Данных)?

В СКД для группировки по дням используется периодичность "День". Для условий отбора также рекомендуется использовать функцию НачалоДня в выражениях или задавать диапазон дат в параметрах.