Разработка и Конфигурация · 10 мин
1С запрос: дата как период — приёмы работы и примеры
Как в запросе 1С использовать дату как период: НАЧАЛОПЕРИОДА, КОНЕЦПЕРИОДА, ПЕРИОДАМИ, параметры виртуальных таблиц. Примеры кода и типичные ошибки.
В языке запросов 1С дата и период — близкие, но не тождественные понятия. Дата хранится с точностью до секунды, а период — это интервал (день, месяц, квартал, год), внутри которого лежит конкретная дата. Когда в условии запроса нужно сравнить не момент времени, а диапазон, разработчик преобразует дату в период с помощью встроенных функций языка запросов.
Практическая задача возникает постоянно: отобрать документы за месяц, сгруппировать продажи по неделям, получить остатки на конец дня, сравнить дату документа с периодом записи регистра сведений. Для каждого сценария в языке запросов есть свой инструмент — функции НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА, конструкция ПЕРИОДАМИ, параметры виртуальных таблиц регистров.
Ошибки в этой области приводят к типичным дефектам: документы «на границе» периода выпадают из отчёта, срез последних возвращает не те данные, а запрос с лишними вычислениями работает медленно. Ниже разобраны рабочие приёмы с примерами кода и критериями проверки результата.
Чем дата отличается от периода в запросе
Тип «Дата» в 1С содержит календарную дату и время с точностью до секунды. Сравнение двух дат — это сравнение моментов времени: условие Документ.Дата = &Дата выполнится только при совпадении до секунды, что почти никогда не нужно в прикладных задачах.
Период — это именованный интервал: день, неделя, декада, месяц, квартал, полугодие, год. Когда пользователь выбирает в отчёте «за март», система должна интерпретировать это как диапазон от 00:00:00 первого числа до 23:59:59 последнего. Преобразование даты в границы такого диапазона и есть суть приёма «дата как период».
Функции НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА
Основной инструмент — пара функций, возвращающих границы периода, в который попадает дата. Синтаксис: НАЧАЛОПЕРИОДА(<Дата>, <Периодичность>) и КОНЕЦПЕРИОДА(<Дата>, <Периодичность>). Например, НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ) вернёт первое число месяца в 00:00:00, а КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ) — последнее число в 23:59:59.
Типовой пример — отбор документов за месяц, в который попадает произвольная дата параметра:
ВЫБРАТЬ
Реализация.Ссылка,
Реализация.Дата
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ)
И КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ)
Функции применимы и к полям выборки, а не только к параметрам. Например, можно вывести начало недели для каждого документа и затем сгруппировать по этому полю — так строят помесячные и понедельные отчёты без дополнительных вычислений на встроенном языке.
Группировка данных по периодам
Для агрегатных отчётов дату приводят к началу периода и группируют по полученному значению. Так суммы продаж, обороты склада или количество документов сворачиваются в месячные или квартальные итоги:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ) КАК Месяц,
СУММА(Продажи.СуммаОборот) КАК Сумма
ИЗ
РегистрНакопления.Продажи.Обороты(, , Регистратор, ) КАК Продажи
СГРУППИРОВАТЬ ПО
НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ)
УПОРЯДОЧИТЬ ПО
Месяц
Важный нюанс: сортировку тоже выполняют по вычисленному полю периода, иначе строки выводятся в произвольном порядке. Если отчёт строится через СКД, ту же задачу решает поле-период в настройках компоновки — но на уровне текста запроса приём с НАЧАЛОПЕРИОДА остаётся универсальным.
Конструкция ПЕРИОДАМИ для итогов
Когда нужны итоги с нарастающей детализацией — год, внутри него кварталы, внутри месяцы — используется секция ИТОГИ ... ПЕРИОДАМИ. Она автоматически формирует группировочные записи по каждому уровню периодичности без ручного вычисления границ:
ВЫБРАТЬ
Продажи.Период КАК Период,
СУММА(Продажи.СуммаОборот) КАК Сумма
ИЗ
РегистрНакопления.Продажи.Обороты(, , Месяц, ) КАК Продажи
ИТОГИ
СУММА(Сумма)
ПО
Период ПЕРИОДАМИ(МЕСЯЦ, &НачалоПериода, &КонецПериода)
Особенность конструкции: при указании границ &НачалоПериода и &КонецПериода в результат попадут и пустые периоды без данных — с нулевыми итогами. Это удобно для графиков и сводных таблиц, где пропуск месяца ломает ось времени, но требует аккуратной обработки пустых строк при программном обходе выборки.
Дата как период в виртуальных таблицах регистров
Регистры сведений с режимом «в пределах периода» и регистры накопления предоставляют виртуальные таблицы, где границы периода передаются параметрами: СрезПервых, СрезПоследних, Остатки, Обороты, ОстаткиИОбороты. Параметр периода здесь — обычная дата, но трактуется она как граница интервала.
Пример получения цен на конец дня указанной даты:
ВЫБРАТЬ
Цены.Номенклатура,
Цены.Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
КОНЕЦПЕРИОДА(&Дата, ДЕНЬ), ) КАК Цены
Тонкость в том, какое значение передавать. Для СрезПоследних момент включается в выборку, поэтому передача КОНЕЦПЕРИОДА(&Дата, ДЕНЬ) захватывает записи, сделанные в течение дня. Для Оборотов параметры задают начало и конец интервала, и снова корректная пара — НАЧАЛОПЕРИОДА для старта и КОНЕЦПЕРИОДА для завершения.
- 1Определите, какой интервал нужен: день, месяц, квартал или произвольный диапазон
- 2Вычислите границы функциями НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА с нужной периодичностью
- 3Передайте границы в условие ГДЕ или в параметры виртуальной таблицы
- 4Выполните запрос в консоли запросов и сверьте, что документы на границах периода попали в выборку
- 5Проверьте время выполнения на реальном объёме данных
Проверка результата и типичные ошибки
Контрольный признак корректного запроса — поведение на границах интервала. Документ от 00:00:00 первого числа должен попадать в выборку, документ от 23:59:59 последнего числа — тоже, а документ следующего дня — нет. Проверяйте это в консоли запросов на тестовых данных до переноса текста в модуль.
Самая частая ошибка — сравнение даты документа с параметром-датой на равенство, когда пользователь вводит дату без времени (00:00:00). В результате за день попадают только документы, проведённые ровно в полночь. Вторая типичная ошибка — использование функции ДАТАВРЕМЯ с жёстко заданными границами там, где период должен вычисляться из параметра.
Как проверить результат
Документ от 00:00:00 первого дня и от 23:59:59 последнего дня присутствуют в выборке
Пограничные документы отсутствуют — границы вычислены неверно
Возвращается актуальное значение с учётом записей внутри дня
Возвращается вчерашнее значение — передано начало дня вместо конца
Запрос отрабатывает за приемлемое время на рабочем объёме
Запрос зависает — проверьте индексы и уберите ИТОГИ ПЕРИОДАМИ
Альтернативы и выбор подхода
Не всегда преобразование нужно делать в тексте запроса. Если границы периода известны заранее (например, из настроек отчёта), их вычисляют один раз на встроенном языке — функциями НачалоМесяца(), КонецМесяца() и аналогами — и передают в запрос готовыми параметрами. Это упрощает текст запроса и позволяет повторно использовать те же значения в нескольких запросах пакета.
В системе компоновки данных периодичность группировки задаётся настройками отчёта, а поля-периоды (День, Месяц, Квартал) платформа формирует автоматически для виртуальных таблиц оборотов. Ручное вычисление через НАЧАЛОПЕРИОДА в СКД обычно требуется только для нестандартных интервалов вроде декад или произвольных производственных недель.
Сравнение вариантов
Универсально, работает с любыми полями и параметрами; минус — границы вычисляются при каждом выполнении
Быстрее и чище текст запроса; подходит, когда границы известны до выполнения, но не работает для вычислений по полям выборки
Даёт многоуровневые итоги и пустые периоды без ручного кода; ограничение — нагрузка на больших таблицах
Самый простой путь для отчётов на компоновке; не подходит для обычных запросов в модулях
FAQ
Как получить все документы за день, если в параметре только дата без времени?
Оберните параметр в границы дня: условие Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, ДЕНЬ) И КОНЕЦПЕРИОДА(&Дата, ДЕНЬ). Тогда в выборку попадут документы с любым временем внутри суток, а не только проведённые в 00:00:00.
Чем отличается периодичность НЕДЕЛЯ от ДЕКАДА в НАЧАЛОПЕРИОДА?
НЕДЕЛЯ приводит дату к понедельнику соответствующей календарной недели. ДЕКАДА делит месяц на три интервала: с 1 по 10, с 11 по 20 и с 21 по конец месяца. Для отчётов по производственным декадам используется именно ДЕКАДА, неделей её заменить нельзя.
Почему СрезПоследних на дату возвращает устаревшее значение?
Чаще всего в параметр передано начало дня (дата с временем 00:00:00), поэтому записи, сделанные позже в тот же день, не учитываются. Передайте КОНЕЦПЕРИОДА(&Дата, ДЕНЬ) — момент конца дня включается в срез.
Можно ли использовать НАЧАЛОПЕРИОДА в секции СГРУППИРОВАТЬ ПО?
Да, функция допустима в группировке, и это стандартный приём для помесячных и поквартальных итогов. Выражение в СГРУППИРОВАТЬ ПО должно совпадать с выражением в списке выборки, а сортировку лучше выполнять по тому же вычисленному полю.
Что выбрать для границы периода: КОНЕЦПЕРИОДА или вычитание секунды из начала следующего дня?
Используйте КОНЕЦПЕРИОДА — функция возвращает корректную последнюю секунду интервала и читается в тексте запроса однозначно. Ручная арифметика с секундами чувствительна к ошибкам и усложняет сопровождение кода.
Работает ли ПЕРИОДАМИ в запросах к обычным таблицам документов, а не к виртуальным таблицам регистров?
Да, конструкция ИТОГИ ПЕРИОДАМИ применима к любому полю типа Дата в выборке, включая дату документа. При указании параметров границ в результат попадут и периоды без документов — с пустыми значениями итогов.
Что важно запомнить
Дата превращается в период функциями НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА с указанием периодичности; для многоуровневых итогов служит ИТОГИ ПЕРИОДАМИ, а в виртуальных таблицах регистров границы передаются параметрами. Всегда проверяйте запрос на границах интервала — именно там скрываются типичные ошибки отбора.