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

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

Перед тем как перейти к практическим примерам, важно понять: в 1С 8.3 период может задаваться как статически (фиксированные даты), так и динамически (относительно текущей даты или параметров). Это влияет на гибкость вашего решения и его применимость в разных сценариях. Например, отчет за"текущий месяц" потребует динамического расчета границ, тогда как анализ данных за"2023 год" можно задать жестко.

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

1. Базовый синтаксис: как указать период в условии WHERE

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

Пример запроса с жестко заданным интервалом:

ВЫБРАТЬ

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

Документ.Дата КАК Дата,

Документ.СуммаДокумента КАК Сумма

ИЗ

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

ГДЕ

Документ.Дата МЕЖДУ'2026-01-01' И'2026-01-31'

Обратите внимание на формат даты: ожидает строковое представление в формате 'ГГГГ-ММ-ДД'. Альтернативный вариант — использовать функцию ДАТАВРЕМЯ, которая создает значение типа Дата из числовых компонентов:

ГДЕ Документ.Дата >= ДАТАВРЕМЯ(2026, 1, 1, 0, 0, 0)

Для относительных периодов (например,"за последние 30 дней") удобно использовать функции работы с датами:

ГДЕ Документ.Дата >= ТЕКУЩАЯДАТА - 30
💡

Если вам нужно получить данные за"текущий день", используйте конструкцию НАЧАЛОДНЯ(ТЕКУЩАЯДАТА) — это гарантирует корректную работу даже при выполнении запроса ночью, когда текущая дата уже следующего дня.

2. Специализированные функции для работы с периодами

Платформа 1С:Предприятие 8 значительно упрощают код и делают его более читаемым. Вот ключевые из них:

  • 📅 НАЧАЛОПЕРИОДА — возвращает первую дату периода (месяца, квартала, года) для указанной даты. Пример: НАЧАЛОПЕРИОДА(ТЕКУЩАЯДАТА,"МЕСЯЦ") вернет 1-е число текущего месяца.
  • 📅 КОНЕЦПЕРИОДА — аналог для последней даты периода. Полезно для задания верхней границы интервала.
  • 🔄 ДОБАВИТЬМЕСЯЦ — сдвигает дату на заданное количество месяцев (может быть отрицательным). Пример: ДОБАВИТЬМЕСЯЦ(ТЕКУЩАЯДАТА, -3) вернет дату 3 месяца назад.
  • 📊 ДЕНЬНЕДЕЛИ — возвращает номер дня недели (1 — понедельник, 7 — воскресенье). Используется для расчета рабочих/выходных дней.

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

ВЫБРАТЬ

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

Документ.Номер

ИЗ

Документ.ПоступлениеТоваровУслуг КАК Документ

ГДЕ

Документ.Дата МЕЖДУ НАЧАЛОПЕРИОДА(ДОБАВИТЬМЕСЯЦ(ТЕКУЩАЯДАТА, -3),"КВАРТАЛ")

И КОНЕЦПЕРИОДА(ДОБАВИТЬМЕСЯЦ(ТЕКУЩАЯДАТА, -3),"КВАРТАЛ")

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

Что делать, если функция возвращает неожиданный период?

Если НАЧАЛОПЕРИОДА(ТЕКУЩАЯДАТА,"КВАРТАЛ") возвращает дату не того квартала, проверьте настройки периода отчетности в конфигураторе (раздел"Администрирование → Настройки программы → Периоды"). Некоторые конфигурации (например, 1С:ERP) позволяют переопределять стандартную логику кварталов.

3. Работа с параметрами: динамические периоды

В реальных задачах редко требуется жестко"зашивать" даты в запрос. Гораздо чаще периоды передаются как параметры — либо из формы ввода, либо рассчитываются в коде. Для этого в используется конструкция ЗНАЧЕНИЕ(Параметр) или ключевое слово &Параметр (в англоязычном синтаксисе).

Пример запроса с параметрами:

ВЫБРАТЬ

Справочник.Номенклатура.Наименование,

РегистрНакопления.ОстаткиТоваров.КоличествоОстаток

ИЗ

РегистрНакопления.ОстаткиТоваров КАК РегистрНакопления.ОстаткиТоваров

ГДЕ

РегистрНакопления.ОстаткиТоваров.Период МЕЖДУ &НачалоПериода И &КонецПериода

Чтобы передать значения параметров из кода, используйте метод УстановитьПараметр:

Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТЕКУЩАЯДАТА));

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

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

ГДЕ Документ.Дата МЕЖДУ &Период.ДатаНачала И &Период.ДатаОкончания

Проверьте, что дата начала <= даты окончания|Убедитесь, что передаваемые значения имеют тип"Дата"|Для регламентных задач добавьте обработку пустых параметров|Тестируйте граничные случаи (например, начало периода = конец периода)-->

4. Типичные ошибки и как их избежать

Ошибки при работе с периодами в запросах часто приводят к некорректным данным или падению производительности. Вот наиболее распространенные проблемы и способы их решения:

  • ⚠️ Неучет временной зоны: Если в базе хранятся даты с временем (тип ДатаВремя), сравнение по дате без учета времени может пропустить записи. Решение: используйте НАЧАЛОДНЯ и КОНЕЦДНЯ для обрезки времени.
  • ⚠️ Пустые параметры: При передаче 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. Оптимизация запросов с периодами

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

  • 🚀 Индексы по полю даты: Убедитесь, что в базе данных создан индекс по полю, используемому в условии периода. В это проверяется через План обмена → Индексы.
  • 🚀 Разделение на подзапросы: Для сложных отчетов разбейте запрос на несколько более простых, а затем объедините результаты в коде.
  • 🚀 Использование временных таблиц: Для повторяющихся расчетов сохраните промежуточные данные во временную таблицу с помощью ПОМЕСТИТЬ.
  • 🚀 Ограничение выборки: Если нужны только последние записи, добавьте ПЕРВЫЕ 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);

Возврат Новый Структура("Начало, Конец", Начало, Конец);

КонецФункции

Пример использования в запросе:

Период = ПолучитьПериодПрошлогоГода;

Запрос.Текст ="ВЫБРАТЬ... ГДЕ Дата МЕЖДУ &Начало И &Конец";

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

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

Преимущество такого подхода — гибкость и возможность повторного использования логики в разных отчетах. Недостаток — усложнение поддержки кода, так как логика периода"размазана" по нескольким функциям.

Как учитывать рабочие дни в периодах?

Для расчета периодов с учетом только рабочих дней (исключая выходные и праздники) используйте функцию РабочиеДниМежду из стандартной библиотеки . Пример:

КоличествоДней = РабочиеДниМежду(НачалоПериода, КонецПериода, Неопределено, Истина);

Подробнее см. синтаксис-помощник по функции РабочиеДниМежду.

Как в запросе получить данные за"текущий день" с учетом времени?

Используйте комбинацию НАЧАЛОДНЯ и КОНЕЦДНЯ:

ГДЕ Документ.ДатаМомента МЕЖДУ НАЧАЛОДНЯ(ТЕКУЩАЯДАТА)

И КОНЕЦДНЯ(ТЕКУЩАЯДАТА)

Это гарантирует попадание в выборку всех документов, созданных с 00:00:00 до 23:59:59 текущего дня.

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

Да, используйте оператор ИЛИ с явным указанием интервалов:

ГДЕ (Документ.Дата МЕЖДУ'2026-01-01' И'2026-01-31')

ИЛИ (Документ.Дата МЕЖДУ'2026-03-01' И'2026-03-31')

Однако такой запрос может быть неоптимальным — рассмотрите возможность разделения на несколько запросов.

Как выбрать период"с начала года по предыдущий месяц"?

Используйте функции НАЧАЛОГОДА и НАЧАЛОМЕСЯЦА с корректировкой:

ГДЕ Документ.Дата >= НАЧАЛОГОДА(ТЕКУЩАЯДАТА)

И Документ.Дата < НАЧАЛОМЕСЯЦА(ТЕКУЩАЯДАТА)

Обратите внимание на строгое неравенство (<) для предыдущего месяца.

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

Основные причины:

  1. Отсутствует индекс по полю даты в базе данных.
  2. В условии используются функции над полем (например, МЕСЯЦ(Дата) = 1).
  3. Период слишком широкий (например,"за все время").
  4. Запрос содержит много JOIN с другими таблицами без ограничений.

Решение: проверьте план запроса, добавьте индексы, сузьте период или разбейте запрос на части.

Как передать период из формы в запрос, если поле имеет тип"Строка"?

Преобразуйте строку в дату с помощью ДАТАВРЕМЯ или СтрокаВДата:

ДатаНачала = СтрокаВДата(Форма.Параметры.ДатаНачала);

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

Для надежности добавьте проверку на корректность преобразования:

Если НЕ ЗначениеЗаполнено(ДатаНачала) Тогда

Сообщить("Некорректный формат даты!");

Возврат;

КонецЕсли;