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

Дата в запросах может быть представлена двумя основными способами: как строковая константа непосредственно в тексте запроса или как параметр, передаваемый из внешней среды (например, из формы документа или отчета). Синтаксис платформы строго регламентирует формат записи, игнорирование которого вызовет ошибку компиляции. Кроме того, важно различать понятия «момент времени» и «период», так как операторы сравнения работают с ними по-разному в зависимости от типа используемого индекса.

В данном материале мы детально разберем синтаксические особенности задания дат, использование специальных функций для работы с границами периодов, а также рассмотрим типичные ошибки, возникающие при фильтрации данных. Вы узнаете, как правильно использовать ключевые слова НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА, и почему иногда простая подстановка значения не дает ожидаемого результата. Особое внимание уделим вопросам производительности и тому, как структура условия влияет на использование индексов СУБД.

Синтаксис задания константы даты в тексте запроса

При написании запроса непосредственно в модуле объекта или в консоли запросов, дату можно задать жестко, используя строковый литерал. Платформа 1С:Предприятие автоматически распознает формат и преобразует строку во внутренний тип Дата. Для этого значение должно быть заключено в кавычки (одинарные или двойные) и соответствовать определенному шаблону, который система понимает без дополнительных преобразований.

Стандартный формат записи даты требует указания года, месяца, дня, а при необходимости — времени с точностью до секунды. Разделителями могут служить дефисы, точки или слэши, однако наиболее универсальным и рекомендуемым форматом является 'ГГГГ-ММ-ДД'. Если требуется указать точное время, оно добавляется через пробел после даты в формате 'ЧЧ:ММ:СС'.

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

ВЫБРАТЬ

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

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

ИЗ

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

ГДЕ

ДокументРеализацияТоваровУслуг.Дата = '&2023-10-25'

В данном примере система автоматически преобразует строку '&2023-10-25' в дату 25 октября 2023 года с временем 00:00:00. Если в базе данных есть документы, проведенные в этот день, но, например, в 14:30, условие равенства не сработает, так как даты не совпадут полностью. Именно поэтому для отбора по дням чаще используют диапазоны или специальные функции, о которых пойдет речь ниже.

⚠️ Внимание: При использовании строковых констант убедитесь, что разделители в дате соответствуют ожиданиям вашей локали или используйте универсальный формат с дефисами. Неправильный порядок дня и месяца (например, американский формат ММ/ДД/ГГГГ вместо европейского ДД.ММ.ГГГГ) может привести к выборке данных за совершенно другой период или ошибке выполнения.

💡

Используйте универсальный формат даты 'ГГГГ-ММ-ДД' в текстах запросов — он наименее зависим от региональных настроек операционной системы и клиента 1С.

Использование параметров в запросах

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

Параметры в тексте запроса обозначаются знаком амперсанда & followed by именем параметра. Имя может состоять из букв, цифр и подчеркивания, но не должно начинаться с цифры. Перед выполнением метода Выполнить() необходимо наполнить коллекцию параметров объекта Запрос соответствующими значениями типов Дата или Строка.

Пример использования параметров для выборки данных за период:

ТекстЗапроса = "

ВЫБРАТЬ

РегистрНакопления.Продажи.Период,

РегистрНакопления.Продажи.Сумма

ИЗ

РегистрНакопления.Продажи КАК Продажи

ГДЕ

Продажи.Период МЕЖДУ &НачалоПериода И &КонецПериода";

Запрос = Новый Запрос(ТекстЗапроса);

Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаНачала));

Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаКонца));

Результат = Запрос.Выполнить();

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

  • 📅 Параметр должен быть объявлен в тексте запроса через символ & перед именем.
  • ⚙️ Значение параметра устанавливается методом УстановитьПараметр до вызова Выполнить.
  • 🚀 Использование параметров позволяет СУБД эффективнее использовать кэширование планов запросов.
📊 Какой способ задания даты вы используете чаще?
Текстовая константа в запросе
Параметры запроса
Глобальные переменные
Функции в условии WHERE

Операторы сравнения и работа с диапазонами

При фильтрации данных по датам критически важно правильно выбрать оператор сравнения. Простое равенство (=) используется редко, так как тип Дата включает в себя время с высокой точностью. Вероятность того, что два события произошли в одну и ту же миллисекунду, ничтожна. Поэтому для отбора данных за определенный день или период используются операторы диапазона: МЕЖДУ (BETWEEN), >= (больше или равно) и <= (меньше или равно).

Оператор МЕЖДУ является инклюзивным, то есть включает в себя обе граничные точки. Если вы пишете условие ГДЕ Дата МЕЖДУ &Начало И &Конец, то в выборку попадут записи, у которых дата равна началу периода, и записи, у которых дата равна концу периода. Это удобно для отбора по месяцам или кварталам, когда границы четко определены.

Однако при работе с конкретными сутками часто возникает проблема «обрезания» времени. Если вы зададите конец периода как 25.10.2023, система интерпретирует это как 25.10.2023 00:00:00. Документы, проведенные 25 числа в 10:00 утра, не попадут в выборку, так как они больше установленного предела. Чтобы избежать этого, необходимо явно указывать конец дня или использовать специальные функции.

Оператор Описание Пример использования Особенность
= Точное совпадение Дата = '&2023-01-01 12:00:00' Редко используется для дат, только для точных временных меток
>, < Строгое неравенство Дата > '&2023-01-01' Не включает граничную дату (00:00:00)
>=, <= Нестрогое неравенство Дата >= '&2023-01-01' Включает граничную дату, удобно для начала периода
МЕЖДУ Диапазон включительно Дата МЕЖДУ &Нач И &Кон Самый читаемый вариант для периодов

⚠️ Внимание: При использовании оператора < для отсечения «завтрашнего» дня помните, что если в базе есть записи с временем 23:59:59, они попадут в выборку текущего дня. Если же есть записи с временем 00:00:00 следующего дня, они будут отсечены. Всегда проверяйте логику границ.

Функции работы с периодами: Начало и Конец

Язык запросов 1С богат встроенными функциями для манипуляции датами, которые позволяют динамически вычислять границы периодов прямо в тексте запроса. Это особенно полезно, когда нужно получить данные за «текущий месяц», «предыдущий квартал» или «начало года» без передачи конкретных дат из кода. Основные функции — это НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА.

Функция НАЧАЛОПЕРИОДА(Дата, Период) возвращает дату начала периода, содержащего указанную дату. Второй параметр определяет granularity ( granularity — зернистость) периода: ГОД, КВАРТАЛ, МЕСЯЦ, ДЕКАДА, НЕДЕЛЯ, ДЕНЬ, ЧАС, МИНУТА, СЕКУНДА. Аналогично работает функция КОНЕЦПЕРИОДА, возвращающая последнюю дату и время указанного периода.

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

ВЫБРАТЬ

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

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

ИЗ

Документ.ЗаказКлиента КАК Документы

ГДЕ

Документы.Дата >= НАЧАЛОПЕРИОДА(&ТекущаяДата, МЕСЯЦ)

И Документы.Дата <= КОНЕЦПЕРИОДА(&ТекущаяДата, МЕСЯЦ)

Использование этих функций в условии ГДЕ может иметь двоякое влияние на производительность. С одной стороны, это удобно и сокращает код. С другой стороны, если функция применяется к полю таблицы (например, НАЧАЛОПЕРИОДА(Документы.Дата, МЕСЯЦ) = &Дата), это может привести к полному сканированию таблицы (Table Scan), так как СУБД не сможет использовать индекс по полю Дата. Правильный подход — применять функции к параметрам, а не к полям таблицы.

Почему нельзя применять функции к полям в условии WHERE?

Когда вы пишете условие вида "ГДЕ НАЧАЛОПЕРИОДА(Таблица.Дата, МЕСЯЦ) = Значение", базе данных приходится вычислять функцию для КАЖДОЙ строки таблицы, чтобы проверить условие. Это отключает использование индекса B-Tree по полю Дата, что приводит к резкому падению производительности на больших объемах данных. Всегда стремитесь к виду "ГДЕ Таблица.Дата >= Значение".

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

При работе с регистрами накопления и срезами (виртуальными таблицами) понятие даты приобретает особый смысл. Виртуальные таблицы, такие как Остатки или Обороты, принимают параметры периода в специальном формате. Здесь дата выступает не просто как поле для сравнения, а как аргумент для формирования среза данных на конкретный момент времени.

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

Пример запроса к виртуальной таблице остатков товаров:

ВЫБРАТЬ

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

ОстаткиТоваров.КоличествоОстаток

ИЗ

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

ГДЕ

ОстаткиТоваров.КоличествоОстаток > 0

В данном случае параметр &Период передается в скобках после имени виртуальной таблицы. Важно понимать, что здесь мы не фильтруем записи по дате в смысле «когда была запись», а запрашиваем состояние системы «на дату». Это фундаментальное отличие работы с регистрами от работы с обычными документами.

  • 🗄️ Виртуальные таблицы регистров требуют указания периода в скобках при обращении.
  • 🕰️ Для таблицы Обороты обычно указываются два параметра: НачалоПериода и КонецПериода.
  • ⚡ Использование виртуальных таблиц оптимизировано платформой и работает быстрее ручных расчетов остатков.

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

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

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

Типичные ошибки и производительность запросов

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

Также стоит упомянуть проблему «вечных» дат. В 1С существует максимальное значение даты (конец 9999 года). Иногда разработчики используют его как бесконечность ('31.12.9999'). Хотя это работает, более правильным с точки зрения семантики является использование значения NULL для открытых интервалов или специальных флагов, если логика предметной области это позволяет.

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

💡

Золотое правило оптимизации: Условия в блоке ГДЕ должны быть построены так, чтобы СУБД могла использовать индексы. Избегайте вычислений над полями таблицы, вычисляйте значения заранее в параметрах запроса.

Как задать дату в запросе 1С, если нужно выбрать данные за «вчерашний день»?

Для выбора данных за вчерашний день лучше всего использовать параметры, вычисленные в коде перед запросом. Вычислите дату вчера: ДатаВчера = ТекущаяДата() - 1. Затем установите диапазон: начало дня вчера (НачалоДня(ДатаВчера)) и конец дня вчера (КонецДня(ДатаВчера)). В запросе используйте условие ГДЕ Дата МЕЖДУ &Нач И &Кон. Использование функций прямо в запросе возможно, но менее гибко.

Почему запрос не находит документы, проведенные 31.12.2023, если я указал дату 31.12.2023?

Скорее всего, вы используете оператор меньше (<) или равенство (=) без учета времени. Если вы написали Дата < '31.12.2023', то система ищет даты строго до 00:00:00 31 декабря. Документы, проведенные в течение дня, имеют время больше 00:00:00. Используйте Дата <= КонецДня('31.12.2023') или оператор МЕЖДУ с корректными границами.

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

Нет, в текстовых константах запроса 1С не поддерживает названия месяцев прописью (например, '25 октября 2023'). Необходимо использовать числовой формат месяца. Допустимы варианты '25.10.2023', '25-10-2023' или '2023-10-25'. Использование слов приведет к ошибке синтаксиса.

В чем разница между ДатаВремя и Дата в контексте запросов?

В языке запросов 1С тип данных unified — это Дата, который всегда включает и дату, и время. Отдельного типа «только дата» без времени в запросах нет. Когда говорят о сравнении «только по дате», имеют в виду игнорирование временной части через приведение к началу/концу дня или использование специальных функций сравнения, но внутреннее представление всегда содержит время.

Как передать дату из формы отчета в параметр запроса?

В модуле объекта отчета, в обработчике события формирования (например, Сформировать), создайте объект запроса. Затем обратитесь к элементу формы, содержащему дату (например, Объект.Период.ДатаНачала), и передайте это значение в метод Запрос.УстановитьПараметр. Убедитесь, что имя параметра в коде совпадает с именем в тексте запроса (без амперсанда при установке).