Как получить массив дней из диапазона дат в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Способ 1. Использование цикла (классический метод)

Самый простой и интуитивно понятный способ — это использование цикла Пока или Для. Основная идея заключается в том, что в 1С к значению типа Дата можно прибавлять число, которое система интерпретирует как секунды. В сутках ровно 86 400 секунд (24 часа * 60 минут * 60 секунд).

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


МассивДат = Новый Массив;
ТекущаяДата = НачалоДня(ДатаНачала);
КонечнаяДата = НачалоДня(ДатаОкончания);

Пока ТекущаяДата <= КонечнаяДата Цикл
    МассивДат.Добавить(ТекущаяДата);
    ТекущаяДата = ТекущаяДата + 86400; // Добавляем одни сутки
КонецЦикла;

Разберем важные нюансы этого кода:

  1. Использование функции НачалоДня(). Это критически важно, так как если в переменной ДатаОкончания время будет установлено на 00:00:01, а мы будем сравнивать её с датой без времени, цикл может отработать некорректно или пропустить последний день.
  2. Математический расчет: 86400 — это константа для шага в один день.
  3. Метод МассивДат.Добавить() сохраняет каждую полученную дату в результирующую коллекцию.

Способ 2. Генерация дат через запрос (без обращения к таблицам БД)

Иногда требуется получить список дат непосредственно в запросе, чтобы сразу соединить их с другими данными (например, остатками или оборотами), не выгружая промежуточные результаты в код 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 дней. Если период больше, нужно добавить еще одно соединение (десятичную разрядность). При необходимости можно использовать варианты построения выборки диапазона дат и чисел с помощью запроса.

Способ 3. Использование производственного календаря

Если в вашей конфигурации ведется производственный календарь (типовые решения БП, ЗУП, ERP), то получить список дат можно простым запросом к регистру сведений. Это самый надежный способ, если вам нужно учитывать не только календарные дни, но и праздники или выходные.

Посмотрим на пример запроса к регистру ДанныеПроизводственногоКалендаря:


ВЫБРАТЬ
    Календарь.Дата КАК Дата
ИЗ
    РегистрСведений.ДанныеПроизводственногоКалендаря КАК Календарь
ГДЕ
    Календарь.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
    И Календарь.ПроизводственныйКалендарь = &КалендарьСсылка

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

Способ 4. Библиотека стандартных подсистем (БСП)

Если вы работаете в современной конфигурации, крайне рекомендуем использовать программный интерфейс БСП. Это избавит вас от необходимости писать собственные алгоритмы. В БСП за работу с датами отвечает общий модуль КалендарныеГрафики.

Разберем программный метод ПолучитьДатыГрафика:


// Получаем массив дат за период
МассивДат = КалендарныеГрафики.ПолучитьДатыГрафика(ПараметрыКалендаря, ДатаНачала, ДатаОкончания);

Этот метод вернет массив дат, учитывая настройки конкретного графика работы. Если вам нужны просто все календарные дни, можно обратиться к функции РазностьДатВКалендарныхДнях или аналогичным вспомогательным процедурам.

Способ 5. Дополнение периодов в СКД

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

Для этого в настройках на вкладке «Детальные записи» (или в группировке по полю даты) нужно:

  1. Установить тип дополнения День.
  2. Указать начальную и конечную дату периода.
  3. После этого в отчете появятся даже те даты, по которым не было никаких движений в базе данных.

Подведение итогов: что выбрать?

Подводя итог, проанализируем, какой метод лучше в конкретной ситуации:

Помните, что при работе с датами всегда стоит использовать НачалоДня(), чтобы избежать ошибок, связанных с неявным указанием времени в параметрах.

← На главную