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

Когда вы пишете запрос к информационной базе, важно четко понимать разницу между точным моментом времени и календарным днем. Операция отсечения времени необходима для корректной группировки журналов документов, расчета остатков на конец дня или построения регистров накопления. В этой статье мы детально разберем механизмы преобразования типов непосредственно на стороне СУБД.

Введение в проблему типов данных

В языке запросов 1С тип данных ДатаВремя является фундаментальным для работы с хронологией событий. Однако при сравнении даты, взятой из формы (где время часто установлено в 00:00:00), с датой из таблицы (где время может быть 14:35:12), условие равенства никогда не выполнится. Именно поэтому возникает потребность в функции НачалоДня.

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

Стоит отметить, что подобные преобразования выполняются на стороне сервера баз данных (MSSQL, PostgreSQL или Oracle), что значительно повышает производительность системы по сравнению с обработкой результатов в коде 1С. Правильное использование конвертации типов в тексте запроса — залог быстрой работы ваших отчетов.

📊 Какой способ обработки даты вы используете чаще?
Прямое сравнение в коде 1С
Функция НачалоДня() в запросе
Таблица значений с периодами
Другой метод

Синтаксис функции НачалоДня

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

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

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

ВЫБРАТЬ

РеализацияТоваровУслуг.Ссылка,

РеализацияТоваровУслуг.Дата

ИЗ

Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

ГДЕ

НачалоДня(РеализацияТоваровУслуг.Дата) = &ДатаОтчета

В приведенном примере параметр &ДатаОтчета должен быть передан в запрос уже очищенным от времени, либо сам запрос должен содержать вызов функции и для параметра. Двойное применение функции избыточно, но не критично для корректности работы. Главное — обеспечить совпадение формата сравниваемых величин.

💡

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

Сравнение периодов и интервалов

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

Классическая ошибка новичков — использование оператора "Меньше или равно" для конечной даты периода без учета времени. Если пользователь выбрал 31 января, а документ проведен в 23:59:59, условие `Дата <= 31.01.2026 00:00:00` его отсечет. Правильный подход требует явного указания конца интервала.

  • 📅 Используйте конструкцию Между.. И.. для задания диапазонов, это читается легче и выполняется оптимизированно.
  • ⏱ Для правой границы периода применяйте функцию КонецДня() или добавляйте одну секунду к началу следующего дня.
  • 🚫 Избегайте ручного вычитания времени в коде 1С перед передачей в запрос, доверьте это движку базы данных.

Рассмотрим пример формирования выборки за месяц. Здесь нам необходимо захватить все события с первой секунды первого дня до последней секунды последнего дня. Явное указание границ через функции языка запросов делает код устойчивым к високосным годам и разной длине месяцев.

ГДЕ

РеализацияТоваровУслуг.Дата >= &НачалоПериода

И РеализацияТоваровУслуг.Дата <= &КонецПериода

При формировании параметров &НачалоПериода и &КонецПериода в коде управляемого приложения рекомендуется использовать встроенные функции НачалоДня и КонецДня языка 1С. Это гарантирует, что в запрос попадут значения, уже подготовленные для корректного сравнения на уровне СУБД.

⚠️ Внимание: При работе с часовыми поясами убедитесь, что сервер 1С и сервер базы данных используют синхронизированное время. Рассинхронизация даже в несколько минут может привести к тому, что документы "потеряются" на стыке периодов.

Оптимизация производительности запросов

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

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

Как работает оптимизатор запросов 1С?

Оптимизатор пытается преобразовать выражения с функциями в диапазонные условия (SARGable), если это возможно. Для функции НачалоДня() это часто удается, превращая вызов в диапазон [День 00:00:00, День 23:59:59].

Альтернативный подход — хранение даты в отдельном реквизите типа Дата (без времени), если такая детализация не требуется для бизнес-логики. Это позволяет выполнять сравнение без каких-либо преобразований, что является самым быстрым вариантом. Однако это требует изменения структуры метаданных.

Метод фильтрации Использование индекса Нагрузка на CPU Рекомендация
Прямое сравнение полей Полное Минимальная Идеальный вариант
Функция НачалоДня() в ГДЕ Частичное / Полное* Средняя Стандартный подход
Преобразование в коде 1С Зависит от реализации Высокая (сеть) Не рекомендуется
Хранение в доп. реквизите Полное Минимальная Для очень больших баз

Звездочка в таблице означает, что использование индекса зависит от версии платформы и конкретной СУБД. В большинстве современных конфигураций на PostgreSQL или MSSQL функция НачалоДня не блокирует использование индекса по дате, если запрос составлен канонически.

💡

Для баз объемом более 100 ГБ рекомендуется проводить тесты производительности конкретных запросов через консоль запросов, проверяя план выполнения.

Работа с виртуальными таблицами и регистрами

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

Виртуальные таблицы часто возвращают срезы на конкретный момент времени. Если вам нужен срез на конец дня, передача даты с временем 23:59:59 может быть избыточной, достаточно передать дату, очищенную через НачалоДня следующего дня, или воспользоваться специальными модификаторами виртуальной таблицы.

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

ВЫБРАТЬ

ОстаткиТоваровНаСкладах.Номенклатура,

ОстаткиТоваровНаСкладах.КоличествоОстаток

ИЗ

РегистрНакопления.ОстаткиТоваров.Остатки(&Период, ) КАК ОстаткиТоваровНаСкладах

В данном случае параметр &Период должен быть передан корректно. Если вы формируете отчет на дату, убедитесь, что в эту дату включены все движения дня. Обычно для регистров остатков это означает запрос на КонецДня(ДатаОтчета).

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

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

Одной из самых распространенных ошибок является попытка сравнить поле типа ДатаВремя с строковым представлением даты. Язык запросов 1С строго типизирован, и неявные преобразования из строки в дату в условиях ГДЕ часто приводят к ошибкам синтаксиса или неверным результатам.

Также разработчики часто забывают о том, что в разных часовых поясах "начало дня" может наступать в разное абсолютное время. Если ваша база данных используется в филиальной сети с разным географическим положением, унификация времени хранения (например, по UTC) и конвертация при отображении становятся обязательными.

  • ❌ Ошибка: Сравнение `Дата = "20.10.2023"` без явного приведения типа.
  • ❌ Ошибка: Использование `Строка(Дата)` внутри запроса для форматирования перед сравнением.
  • ✅ Решение: Всегда передавать параметры типизированными объектами 1С.

Еще один подводный камень — работа с NULL-значениями. Функция НачалоДня от пустой ссылки или неопределенного значения вернет ошибку. Перед применением функции в запросе убедитесь, что поле заполнено, используя конструкцию ЕСТЬNULL или предварительную фильтрацию.

☑️ Проверка корректности запроса

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

FAQ: Часто задаваемые вопросы

Можно ли использовать функцию КонецДня() в запросе?

Да, функция КонецДня() полностью аналогична НачалоДня(), но возвращает время 23:59:59. Она полезна при формировании правой границы интервала для оператора Между.

Как получить только дату в коде 1С перед запросом?

Используйте встроенную функцию языка 1С НачалоДня(ТекущаяДата()). Это создаст объект даты с обнуленным временем, который можно безопасно передавать в параметр запроса.

Влияет ли использование НачалоДня на скорость работы базы?

Влияние минимально на современных серверах. Оптимизатор запросов 1С старается преобразовать такие условия в диапазоны. Существенное замедление возможно только при отсутствии индексов по полям даты.

Что делать, если нужно сравнить только месяц и год?

Для этого существуют функции НачалоМесяца() и КонецМесяца(). Логика та же: приводите обе сравниваемые даты к началу месяца перед проверкой на равенство.

Можно ли убрать время через конвертацию типа в строку?

Технически можно, но это крайне неэффективно. Сравнение строк работает медленнее сравнения чисел (дат), и вы теряете возможность использования индексации по дате. Используйте только специализированные функции даты.