Работа с периодами в запросах 1С:Предприятие 8 — одна из самых востребованных задач при разработке отчетов, обработок и аналитических систем. Неправильно указанный интервал может привести к искажению данных, замедлению выполнения или даже ошибкам в логике программы. Эта статья поможет разобраться, как грамотно формировать условия по датам, какие синтаксические конструкции использовать для разных сценариев и как избежать типичных ошибок.
Особенность работы с периодами в 1С заключается в том, что платформа предоставляет несколько способов их задания — от простых сравнений до специализированных функций вроде НАЧАЛОПЕРИОДА или КОНЕЦПЕРИОДА. При этом выбор подходящего метода зависит не только от задачи, но и от версии платформы, объема данных и требований к производительности. Далее мы рассмотрим все ключевые аспекты — от базового синтаксиса до оптимизации сложных запросов.
Перед тем как перейти к практическим примерам, важно понять: в 1С 8.3 период может задаваться как статически (фиксированные даты), так и динамически (относительно текущей даты или параметров). Это влияет на гибкость вашего решения и его применимость в разных сценариях. Например, отчет за"текущий месяц" потребует динамического расчета границ, тогда как анализ данных за"2023 год" можно задать жестко.
1. Базовый синтаксис: как указать период в условии WHERE
Самый простой способ ограничить выборку по датам — использовать стандартные операторы сравнения в секции ГДЕ (или WHERE в англоязычном синтаксисе). Платформа 1С поддерживает все классические операции: =, >, >=, <, <=, а также МЕЖДУ (BETWEEN).
Пример запроса с жестко заданным интервалом:
ВЫБРАТЬ
Документ.Ссылка КАК Ссылка,
Документ.Дата КАК Дата,
Документ.СуммаДокумента КАК Сумма
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
ГДЕ
Документ.Дата МЕЖДУ'2026-01-01' И'2026-01-31'
Обратите внимание на формат даты: 1С ожидает строковое представление в формате 'ГГГГ-ММ-ДД'. Альтернативный вариант — использовать функцию ДАТАВРЕМЯ, которая создает значение типа Дата из числовых компонентов:
ГДЕ Документ.Дата >= ДАТАВРЕМЯ(2026, 1, 1, 0, 0, 0)
Для относительных периодов (например,"за последние 30 дней") удобно использовать функции работы с датами:
ГДЕ Документ.Дата >= ТЕКУЩАЯДАТА - 30
Если вам нужно получить данные за"текущий день", используйте конструкцию НАЧАЛОДНЯ(ТЕКУЩАЯДАТА) — это гарантирует корректную работу даже при выполнении запроса ночью, когда текущая дата уже следующего дня.
2. Специализированные функции для работы с периодами
Платформа 1С:Предприятие 8 значительно упрощают код и делают его более читаемым. Вот ключевые из них:
- 📅
НАЧАЛОПЕРИОДА— возвращает первую дату периода (месяца, квартала, года) для указанной даты. Пример:НАЧАЛОПЕРИОДА(ТЕКУЩАЯДАТА,"МЕСЯЦ")вернет 1-е число текущего месяца. - 📅
КОНЕЦПЕРИОДА— аналог для последней даты периода. Полезно для задания верхней границы интервала. - 🔄
ДОБАВИТЬМЕСЯЦ— сдвигает дату на заданное количество месяцев (может быть отрицательным). Пример:ДОБАВИТЬМЕСЯЦ(ТЕКУЩАЯДАТА, -3)вернет дату 3 месяца назад. - 📊
ДЕНЬНЕДЕЛИ— возвращает номер дня недели (1 — понедельник, 7 — воскресенье). Используется для расчета рабочих/выходных дней.
Пример использования в запросе для получения данных за предыдущий квартал:
ВЫБРАТЬ
Документ.Дата,
Документ.Номер
ИЗ
Документ.ПоступлениеТоваровУслуг КАК Документ
ГДЕ
Документ.Дата МЕЖДУ НАЧАЛОПЕРИОДА(ДОБАВИТЬМЕСЯЦ(ТЕКУЩАЯДАТА, -3),"КВАРТАЛ")
И КОНЕЦПЕРИОДА(ДОБАВИТЬМЕСЯЦ(ТЕКУЩАЯДАТА, -3),"КВАРТАЛ")
Важный нюанс: функции Если НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА в некоторых конфигурациях могут работать медленнее, чем прямые сравнения, если индексы по полю даты отсутствуют. В таких случаях имеет смысл заранее вычислить границы периода в коде и подставить их как параметры.
Что делать, если функция возвращает неожиданный период?
НАЧАЛОПЕРИОДА(ТЕКУЩАЯДАТА,"КВАРТАЛ") возвращает дату не того квартала, проверьте настройки периода отчетности в конфигураторе (раздел"Администрирование → Настройки программы → Периоды"). Некоторые конфигурации (например, 1С:ERP) позволяют переопределять стандартную логику кварталов.
3. Работа с параметрами: динамические периоды
В реальных задачах редко требуется жестко"зашивать" даты в запрос. Гораздо чаще периоды передаются как параметры — либо из формы ввода, либо рассчитываются в коде. Для этого в 1С используется конструкция ЗНАЧЕНИЕ(Параметр) или ключевое слово &Параметр (в англоязычном синтаксисе).
Пример запроса с параметрами:
ВЫБРАТЬ
Справочник.Номенклатура.Наименование,
РегистрНакопления.ОстаткиТоваров.КоличествоОстаток
ИЗ
РегистрНакопления.ОстаткиТоваров КАК РегистрНакопления.ОстаткиТоваров
ГДЕ
РегистрНакопления.ОстаткиТоваров.Период МЕЖДУ &НачалоПериода И &КонецПериода
Чтобы передать значения параметров из кода, используйте метод УстановитьПараметр:
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТЕКУЩАЯДАТА));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТЕКУЩАЯДАТА));
Для упрощения работы с формами ввода периодов в 1С существует стандартный реквизит Период (тип Структура с полями ДатаНачала и ДатаОкончания). Его можно добавить на форму отчета через конструктор или вручную, а затем использовать в запросе:
ГДЕ Документ.Дата МЕЖДУ &Период.ДатаНачала И &Период.ДатаОкончания
Проверьте, что дата начала <= даты окончания|Убедитесь, что передаваемые значения имеют тип"Дата"|Для регламентных задач добавьте обработку пустых параметров|Тестируйте граничные случаи (например, начало периода = конец периода)-->
4. Типичные ошибки и как их избежать
Ошибки при работе с периодами в запросах 1С часто приводят к некорректным данным или падению производительности. Вот наиболее распространенные проблемы и способы их решения:
- ⚠️ Неучет временной зоны: Если в базе хранятся даты с временем (тип
ДатаВремя), сравнение по дате без учета времени может пропустить записи. Решение: используйтеНАЧАЛОДНЯиКОНЕЦДНЯдля обрезки времени. - ⚠️ Пустые параметры: При передаче
NULLв параметр периода запрос может вернуть все записи. Решение: добавьте проверкуЕСТЬNULL(&Параметр, ЗНАЧЕНИЕ(Дата.Минимальная)). - ⚠️ Неэффективные индексы: Запросы с функциями над полем даты (например,
МЕСЯЦ(Документ.Дата) = 1) не используют индексы. Решение: перепишите условие какДокумент.Дата МЕЖДУ'2026-01-01' И'2026-01-31'.
Пример ошибочного и исправленного варианта:
```bsl
// Некорректно (не использует индекс):
ГДЕ ГОД(Документ.Дата) = 2026
// Корректно:
ГДЕ Документ.Дата >= ДАТАВРЕМЯ(2026, 1, 1, 0, 0, 0)
И Документ.Дата < ДАТАВРЕМЯ(2026, 1, 1, 0, 0, 0)
```
⚠️ Внимание: В некоторых версиях 1С:Предприятие 8.3 (до 8.3.20) функцияКОНЕЦПЕРИОДАдля квартала могла возвращать неверную дату из-за ошибки в алгоритме. Перед использованием проверьте актуальность вашей платформы или используйте альтернативный расчет черезДОБАВИТЬМЕСЯЦ.
5. Оптимизация запросов с периодами
Запросы с большими временными интервалами могут выполняться медленно, особенно если таблица содержит миллионы записей. Вот ключевые приемы оптимизации:
- 🚀 Индексы по полю даты: Убедитесь, что в базе данных создан индекс по полю, используемому в условии периода. В 1С это проверяется через
План обмена → Индексы. - 🚀 Разделение на подзапросы: Для сложных отчетов разбейте запрос на несколько более простых, а затем объедините результаты в коде.
- 🚀 Использование временных таблиц: Для повторяющихся расчетов сохраните промежуточные данные во временную таблицу с помощью
ПОМЕСТИТЬ. - 🚀 Ограничение выборки: Если нужны только последние записи, добавьте
ПЕРВЫЕ 1000или используйтеПОРЯДОК ПО Дата УБЫВ.
Пример оптимизированного запроса с использованием временной таблицы:
// Сначала сохраняем IDs документов за период во временную таблицу
ВЫБРАТЬ РАЗЛИЧНЫЕ
Документ.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТДокументыПериода
ИЗ
Документ.ЗаказПокупателя КАК Документ
ГДЕ
Документ.Дата МЕЖДУ &Начало И &Конец;
// Затем joining с основной таблицей по предварительно отобранным данным
ВЫБРАТЬ
ВТДокументыПериода.Ссылка КАК Ссылка,
Документ.СуммаДокумента КАК Сумма
ИЗ
ВТДокументыПериода КАК ВТДокументыПериода
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказПокупателя КАК Документ
ПО ВТДокументыПериода.Ссылка = Документ.Ссылка
Для анализа производительности запросов используйте План запроса (доступен в конфигураторе через меню Отладка → Показать план запроса). Он покажет, какие операции наиболее затратные и где отсутствуют индексы.
| Метод оптимизации | Применимость | Ожидаемый эффект |
|---|---|---|
| Добавление индекса по дате | Любые запросы с фильтрацией по дате | Ускорение в 10–100 раз |
Использование ПОМЕСТИТЬ |
Сложные отчеты с повторяющимися подзапросами | Снижение нагрузки на 30–50% |
| Разделение на подзапросы | Запросы с множеством JOIN и условий | Упрощение плана выполнения |
Ограничение выборки (ПЕРВЫЕ N) |
Отображение топ-N записей | Снижение потребления памяти |
6. Практический пример: отчет по продажам с гибким периодом
Рассмотрим полный пример создания отчета по продажам с возможностью выбора периода через форму. Этот сценарий покрывает большинство типичных задач: динамический период, группировка данных и вывод в табличный документ.
Шаг 1. Создайте форму отчета с реквизитом Период (тип Структура) и элементами управления для ввода дат. В модуле формы добавьте обработчик кнопки"Сформировать":
Процедура СформироватьОтчет(Команда)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Документ.Контрагент КАК Контрагент,
| СУММА(Документ.СуммаДокумента) КАК Итого
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Документ
|ГДЕ
| Документ.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
|СГРУППИРОВАТЬ ПО
| Документ.Контрагент";
Запрос.УстановитьПараметр("ДатаНачала", Период.ДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончания", Период.ДатаОкончания);
Результат = Запрос.Выполнить;
ВывестиРезультат(Результат);
КонецПроцедуры
Шаг 2. Реализуйте процедуру ВывестиРезультат для отображения данных в табличном документе:
Процедура ВывестиРезультат(РезультатЗапроса)
Таблица = Новый ТабличныйДокумент;
Область = Таблица.Область;
// Заголовки колонок
Область.УстановитьТекст(1, 1,"Контрагент");
Область.УстановитьТекст(1, 2,"Сумма продаж");
Строка = 2;
Для Каждого Строчка Из РезультатЗапроса Выбрать Цикл
Область.УстановитьТекст(Строка, 1, Строчка.Контрагент.Наименование);
Область.УстановитьТекст(Строка, 2, Формат(Строчка.Итого,"ЧДЦ=2"));
Строка = Строка + 1;
КонецЦикла;
Таблица.Показать;
КонецПроцедуры
Шаг 3. Добавьте на форму обработку события ПриОткрытии для установки периода по умолчанию (например, текущий месяц):
Процедура ПриОткрытии
Период.ДатаНачала = НачалоМесяца(ТЕКУЩАЯДАТА);
Период.ДатаОкончания = КонецМесяца(ТЕКУЩАЯДАТА);
КонецПроцедуры
Всегда проверяйте корректность передачи параметров в запрос! Даже если в форме отображаются верные даты, ошибка в коде может привести к передаче пустых значений или неверного типа данных.
7. Особенности работы с виртуальными таблицами
При работе с виртуальными таблицами (например, РегистрНакопления.Остатки или РегистрСведений.ЦеныНоменклатуры) период указывается не в секции ГДЕ, а в параметрах виртуальной таблицы. Это принципиальное отличие от обычных таблиц!
Синтаксис для виртуальных таблиц:
ВЫБРАТЬ
ОстаткиТоваров.Номенклатура КАК Номенклатура,
ОстаткиТоваров.КоличествоОстаток КАК Остаток
ИЗ
РегистрНакопления.ОстаткиТоваров.Остатки(
&ДатаОтчета,
Номенклатура В (&СписокНоменклатуры)
) КАК ОстаткиТоваров
Ключевые моменты:
- 🔹 Параметр
&ДатаОтчетаопределяет"срез" данных на указанную дату (включительно). - 🔹 Для анализа динамики (например, обороты за период) используйте виртуальную таблицу
Оборотыс двумя параметрами дат:
ВЫБРАТЬ
ОборотыТоваров.Номенклатура,
ОборотыТоваров.КоличествоПриход КАК Приход,
ОборотыТоваров.КоличествоРасход КАК Расход
ИЗ
РегистрНакопления.ОстаткиТоваров.Обороты(
&ДатаНачала,
&ДатаОкончания,
Номенклатура В (&СписокНоменклатуры)
) КАК ОборотыТоваров
⚠️ Внимание: Виртуальные таблицыОборотыиОстаткимогут возвращать разные результаты при одинаковых параметрах дат!Оборотыпоказывает движения за интервал, аОстатки— состояние на конкретную дату. Для анализа прихода/расхода за период всегда используйтеОбороты.
8. Альтернативные подходы: программное формирование периода
Иногда удобнее рассчитывать границы периода не в запросе, а в коде на встроенном языке. Это актуально для сложной логики (например,"последний полный квартал" или"период с начала года до предыдущего месяца"). Вот несколько полезных функций для таких случаев:
Функция ПолучитьНачалоТекущегоКвартала
ТекущийМесяц = МЕСЯЦ(ТЕКУЩАЯДАТА);
Квартал = Цел(ТекущийМесяц / 3) + 1;
ПервыйМесяцКвартала = (Квартал - 1) * 3 + 1;
Возврат ДАТАВРЕМЯ(ГОД(ТЕКУЩАЯДАТА), ПервыйМесяцКвартала, 1, 0, 0, 0);
КонецФункции
Функция ПолучитьПериодПрошлогоГода
Начало = ДАТАВРЕМЯ(ГОД(ТЕКУЩАЯДАТА) - 1, 1, 1, 0, 0, 0);
Конец = ДАТАВРЕМЯ(ГОД(ТЕКУЩАЯДАТА) - 1, 12, 31, 23, 59, 59);
Возврат Новый Структура("Начало, Конец", Начало, Конец);
КонецФункции
Пример использования в запросе:
Период = ПолучитьПериодПрошлогоГода;
Запрос.Текст ="ВЫБРАТЬ... ГДЕ Дата МЕЖДУ &Начало И &Конец";
Запрос.УстановитьПараметр("Начало", Период.Начало);
Запрос.УстановитьПараметр("Конец", Период.Конец);
Преимущество такого подхода — гибкость и возможность повторного использования логики в разных отчетах. Недостаток — усложнение поддержки кода, так как логика периода"размазана" по нескольким функциям.
Для расчета периодов с учетом только рабочих дней (исключая выходные и праздники) используйте функцию Подробнее см. синтаксис-помощник по функции Как учитывать рабочие дни в периодах?
РабочиеДниМежду из стандартной библиотеки 1С. Пример:
КоличествоДней = РабочиеДниМежду(НачалоПериода, КонецПериода, Неопределено, Истина);РабочиеДниМежду.
Как в запросе получить данные за"текущий день" с учетом времени?
Используйте комбинацию НАЧАЛОДНЯ и КОНЕЦДНЯ:
ГДЕ Документ.ДатаМомента МЕЖДУ НАЧАЛОДНЯ(ТЕКУЩАЯДАТА)
И КОНЕЦДНЯ(ТЕКУЩАЯДАТА)
Это гарантирует попадание в выборку всех документов, созданных с 00:00:00 до 23:59:59 текущего дня.
Можно ли в одном запросе получить данные за несколько не связанных периодов?
Да, используйте оператор ИЛИ с явным указанием интервалов:
ГДЕ (Документ.Дата МЕЖДУ'2026-01-01' И'2026-01-31')
ИЛИ (Документ.Дата МЕЖДУ'2026-03-01' И'2026-03-31')
Однако такой запрос может быть неоптимальным — рассмотрите возможность разделения на несколько запросов.
Как выбрать период"с начала года по предыдущий месяц"?
Используйте функции НАЧАЛОГОДА и НАЧАЛОМЕСЯЦА с корректировкой:
ГДЕ Документ.Дата >= НАЧАЛОГОДА(ТЕКУЩАЯДАТА)
И Документ.Дата < НАЧАЛОМЕСЯЦА(ТЕКУЩАЯДАТА)
Обратите внимание на строгое неравенство (<) для предыдущего месяца.
Почему запрос с периодом выполняется медленно?
Основные причины:
- Отсутствует индекс по полю даты в базе данных.
- В условии используются функции над полем (например,
МЕСЯЦ(Дата) = 1). - Период слишком широкий (например,"за все время").
- Запрос содержит много JOIN с другими таблицами без ограничений.
Решение: проверьте план запроса, добавьте индексы, сузьте период или разбейте запрос на части.
Как передать период из формы в запрос, если поле имеет тип"Строка"?
Преобразуйте строку в дату с помощью ДАТАВРЕМЯ или СтрокаВДата:
ДатаНачала = СтрокаВДата(Форма.Параметры.ДатаНачала);
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ДатаНачала));
Для надежности добавьте проверку на корректность преобразования:
Если НЕ ЗначениеЗаполнено(ДатаНачала) Тогда
Сообщить("Некорректный формат даты!");
Возврат;
КонецЕсли;