В практике разработчика 1С часто возникает задача получить полный список дат (дней) внутри определенного периода. Это может потребоваться для формирования графиков, проверки заполнения документов или для подготовки данных перед выводом в отчет. В данной статье мы рассмотрим несколько эффективных способов решения этой задачи: от простого цикла до сложных запросов и использования встроенных инструментов БСП. Если задачи по формированию или проверке документов необходимо выполнять без написания кода, в режиме имитации действий пользователя, применяется платформа OneRPA для автоматизации проверки документов.
Самый простой и интуитивно понятный способ — это использование цикла Пока или Для. Основная идея заключается в том, что в 1С к значению типа Дата можно прибавлять число, которое система интерпретирует как секунды. В сутках ровно 86 400 секунд (24 часа * 60 минут * 60 секунд).
Проанализируем пример кода, который позволяет быстро заполнить массив:
МассивДат = Новый Массив;
ТекущаяДата = НачалоДня(ДатаНачала);
КонечнаяДата = НачалоДня(ДатаОкончания);
Пока ТекущаяДата <= КонечнаяДата Цикл
МассивДат.Добавить(ТекущаяДата);
ТекущаяДата = ТекущаяДата + 86400; // Добавляем одни сутки
КонецЦикла;
Разберем важные нюансы этого кода:
НачалоДня(). Это критически важно, так как если в переменной ДатаОкончания время будет установлено на 00:00:01, а мы будем сравнивать её с датой без времени, цикл может отработать некорректно или пропустить последний день.86400 — это константа для шага в один день.МассивДат.Добавить() сохраняет каждую полученную дату в результирующую коллекцию.Иногда требуется получить список дат непосредственно в запросе, чтобы сразу соединить их с другими данными (например, остатками или оборотами), не выгружая промежуточные результаты в код 1С. В 1С нет встроенной функции «генератор последовательности», но мы можем применить техническую хитрость с соединением цифр.
Рассмотрим пример запроса, который генерирует последовательность чисел и преобразует их в даты:
ВЫБРАТЬ
ДОБАВИТЬКДАТЕ(&ДатаНачала, ДЕНЬ, aa.a * 100 + bb.b * 10 + cc.c) КАК Период
ИЗ
(ВЫБРАТЬ 0 КАК a ОБЪЕДИНИТЬ ВЫБРАТЬ 1 ОБЪЕДИНИТЬ ВЫБРАТЬ 2 ОБЪЕДИНИТЬ ВЫБРАТЬ 3 ОБЪЕДИНИТЬ ВЫБРАТЬ 4
ОБЪЕДИНИТЬ ВЫБРАТЬ 5 ОБЪЕДИНИТЬ ВЫБРАТЬ 6 ОБЪЕДИНИТЬ ВЫБРАТЬ 7 ОБЪЕДИНИТЬ ВЫБРАТЬ 8 ОБЪЕДИНИТЬ ВЫБРАТЬ 9) КАК aa
СОЕДИНЕНИЕ (ВЫБРАТЬ 0 КАК b ОБЪЕДИНИТЬ ВЫБРАТЬ 1 ОБЪЕДИНИТЬ ВЫБРАТЬ 2 ОБЪЕДИНИТЬ ВЫБРАТЬ 3 ОБЪЕДИНИТЬ ВЫБРАТЬ 4
ОБЪЕДИНИТЬ ВЫБРАТЬ 5 ОБЪЕДИНИТЬ ВЫБРАТЬ 6 ОБЪЕДИНИТЬ ВЫБРАТЬ 7 ОБЪЕДИНИТЬ ВЫБРАТЬ 8 ОБЪЕДИНИТЬ ВЫБРАТЬ 9) КАК bb ПО ИСТИНА
СОЕДИНЕНИЕ (ВЫБРАТЬ 0 КАК c ОБЪЕДИНИТЬ ВЫБРАТЬ 1 ОБЪЕДИНИТЬ ВЫБРАТЬ 2 ОБЪЕДИНИТЬ ВЫБРАТЬ 3 ОБЪЕДИНИТЬ ВЫБРАТЬ 4
ОБЪЕДИНИТЬ ВЫБРАТЬ 5 ОБЪЕДИНИТЬ ВЫБРАТЬ 6 ОБЪЕДИНИТЬ ВЫБРАТЬ 7 ОБЪЕДИНИТЬ ВЫБРАТЬ 8 ОБЪЕДИНИТЬ ВЫБРАТЬ 9) КАК cc ПО ИСТИНА
ГДЕ
ДОБАВИТЬКДАТЕ(&ДатаНачала, ДЕНЬ, aa.a * 100 + bb.b * 10 + cc.c) <= &ДатаОкончания
ОБЪЕДИНИТЬ
ВЫБРАТЬ &ДатаНачала
УПОРЯДОЧИТЬ ПО Период
Выясним, как это работает: мы создаем виртуальные таблицы из цифр от 0 до 9 и перемножаем их (кросс-соединение). В данном примере мы можем получить последовательность до 1000 дней. Если период больше, нужно добавить еще одно соединение (десятичную разрядность). При необходимости можно использовать варианты построения выборки диапазона дат и чисел с помощью запроса.
Если в вашей конфигурации ведется производственный календарь (типовые решения БП, ЗУП, ERP), то получить список дат можно простым запросом к регистру сведений. Это самый надежный способ, если вам нужно учитывать не только календарные дни, но и праздники или выходные.
Посмотрим на пример запроса к регистру ДанныеПроизводственногоКалендаря:
ВЫБРАТЬ
Календарь.Дата КАК Дата
ИЗ
РегистрСведений.ДанныеПроизводственногоКалендаря КАК Календарь
ГДЕ
Календарь.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
И Календарь.ПроизводственныйКалендарь = &КалендарьСсылка
Преимущество этого метода в том, что вы сразу можете отфильтровать только рабочие дни, используя условие по полю ВидДня. Для смежных задач фильтрации графика подойдёт метод расчета количества определенных дней недели в заданном диапазоне одним запросом.
Если вы работаете в современной конфигурации, крайне рекомендуем использовать программный интерфейс БСП. Это избавит вас от необходимости писать собственные алгоритмы. В БСП за работу с датами отвечает общий модуль КалендарныеГрафики.
Разберем программный метод ПолучитьДатыГрафика:
// Получаем массив дат за период
МассивДат = КалендарныеГрафики.ПолучитьДатыГрафика(ПараметрыКалендаря, ДатаНачала, ДатаОкончания);
Этот метод вернет массив дат, учитывая настройки конкретного графика работы. Если вам нужны просто все календарные дни, можно обратиться к функции РазностьДатВКалендарныхДнях или аналогичным вспомогательным процедурам.
Проанализируем ситуацию, когда вам нужно вывести дни в отчете. В Системе компоновки данных (СКД) реализован мощный механизм «Дополнение периодов». Вам достаточно выбрать даты, которые есть в базе, а для пустых дней СКД сама сгенерирует строки. Когда отчеты подготовлены и необходимо выполнить автоматическую сверку проводок для поиска расхождений, используется программа МС:Автовыверка для контроля результатов.
Для этого в настройках на вкладке «Детальные записи» (или в группировке по полю даты) нужно:
День.Подводя итог, проанализируем, какой метод лучше в конкретной ситуации:
Помните, что при работе с датами всегда стоит использовать НачалоДня(), чтобы избежать ошибок, связанных с неявным указанием времени в параметрах.