Как добавить определенное количество рабочих дней к дате в 1С

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

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

Постановка задачи и типичные ошибки

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

Рассмотрим распространенную ошибку, которую часто совершают новички. Попытка сначала вычислить «примерную» дату окончания, прибавив календарные дни, а затем пытаться «докинуть» сверху количество выходных, которые попали в этот интервал, обычно приводит к неверным результатам. Проблема в том, что добавленные «компенсационные» дни сами могут выпасть на выходные, что потребует еще одной итерации расчета. Именно поэтому наиболее надежными являются методы последовательного перебора или строгие математические алгоритмы.

Решение №1: Универсальный метод с использованием цикла

Самый понятный и простой в реализации способ (который поможет реализовать Консоль кода + ИИ-помощник Консоль кода и ИИ-помощник для разработки на 1С) — это последовательный перебор дней. Мы будем двигаться от начальной даты шаг за шагом, проверять каждый день на «рабочесть» и увеличивать счетчик, пока не достигнем нужного количества рабочих дней.

Разберем готовый код функции, который успешно прошел проверку:


&НаКлиенте
Функция ДобавитьРабочийДень(ДатаНачала, КоличествоРабочихДней)
    // Инициализируем переменную для текущей даты
    ТекущаяДата = ДатаНачала;
    КоличествоДобавленныхРабочихДней = 0;
    
    // Если нужно добавить 0 дней, сразу возвращаем исходную дату
    Если КоличествоРабочихДней = 0 Тогда
        Возврат ДатаНачала;
    КонецЕсли;

    // Цикл продолжается, пока не наберем нужное количество рабочих дней
    Пока КоличествоДобавленныхРабочихДней < КоличествоРабочихДней Цикл
        // Добавляем к дате одни сутки (86400 секунд)
        ТекущаяДата = ТекущаяДата + 86400;
        
        // Проверяем номер дня недели (1 - понедельник, 7 - воскресенье)
        Если ДеньНедели(ТекущаяДата) <= 5 Тогда
            // Если это будний день, увеличиваем счетчик
            КоличествоДобавленныхРабочихДней = КоличествоДобавленныхРабочихДней + 1;
        КонецЕсли;
    КонецЦикла;

    Возврат ТекущаяДата;
КонецФункции

Проанализируем ключевые моменты этого кода (используя Статический анализатор кода автоматическая проверка кода на ошибки):

  1. Использование константы 86400. В 1С прибавление числа к дате означает прибавление секунд. В одних сутках 24 часа * 60 минут * 60 секунд = 86400 секунд.
  2. Функция ДеньНедели() — это встроенный механизм платформы, который возвращает число от 1 до 7. Это позволяет нам легко отсечь 6 (суббота) и 7 (воскресенье).
  3. Переменная ДатаНачала остается неизменной, так как мы работаем с локальной переменной ТекущаяДата.

Решение №2: Математический алгоритм (оптимизация без цикла)

Если нам нужно прибавить очень большое количество дней (например, несколько тысяч), цикл может работать недостаточно быстро — для этого есть библиотека математических моделей распределения ресурсов. В таких случаях мы можем воспользоваться математическим подходом. Основная идея заключается в том, чтобы вычислить количество полных недель.

Рассмотрим логику этого процесса:

  1. Вычисляем количество полных рабочих недель путем целочисленного деления КоличествоРабочихДней на 5. Каждая такая неделя гарантированно добавляет 7 календарных дней.
  2. Находим остаток дней (КоличествоРабочихДней % 5).
  3. Прибавляем полные недели к дате.
  4. Добавляем остаток дней, проверяя, не перешагнули ли мы через выходные. Если перешагнули — добавляем еще 2 дня.

Этот метод значительно сложнее в отладке (поможет инструмент для пошаговой отладки кода 1С), так как нужно учитывать, на какой день недели выпала исходная дата. Например, если мы начинаем в пятницу и добавляем 1 рабочий день, мы должны получить понедельник. Если начинаем в субботу, алгоритм должен сначала «нормализовать» дату до ближайшего понедельника.

Решение №3: Использование производственного календаря и БСП

В реальных конфигурациях (таких как УТ 11, БП 3.0 или ЗУП 3.1) разработчики редко пишут подобные функции с нуля. Платформа и Библиотека стандартных подсистем (БСП) предоставляют более мощные инструменты. Главный минус предыдущих способов — они не учитывают праздничные дни (1 января, 9 мая и т.д.).

Для корректного учета всех выходных и праздников в 1С используется объект Производственный календарь. Рассмотрим, как это работает программно:

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


// Пример использования механизмов БСП
ДатаЗавершения = КалендарныеГрафики.ПолучитьДатуЗавершения(КалендарьСсылка, ДатаНачала, КоличествоРабочихДней);

Преимущества этого подхода:

Рекомендации по улучшению кода

Если вы все же решили использовать самописную функцию, проанализируем, как сделать её более надежной:

1. Обработка отрицательных значений: Хорошая функция должна уметь отнимать рабочие дни. Для этого нужно добавить проверку: если КоличествоРабочихДней < 0, то мы должны вычитать секунды и проверять дни в обратном порядке.

2. Проверка входных параметров: Всегда проверяйте, заполнена ли дата. В 1С пустая дата — это '00010101'. Работа с ней в цикле может привести к непредсказуемым результатам.

3. Вынос расчета на сервер: Операции с датами и тем более запросы к календарям должны выполняться в серверном контексте (директива &НаСервере). Это ускоряет работу и соответствует стандартам разработки 1С.

Выясним причину, почему в первом сообщении автора код не работал: он пытался использовать массив для хранения дат и сложную логику «увеличения периода», при которой количество выходных считалось один раз. Это классическая логическая ловушка. Использование простого счетчика внутри цикла (как во втором варианте решения) — самый надежный способ для начинающего программиста понять механику работы с датами в 1С.

Подводя итог, для простых учебных задач или скриптов «на коленке» идеально подходит цикл с проверкой ДеньНедели(). Для серьезных учетных систем всегда выбирайте Производственный календарь и функции БСП, чтобы не заставлять пользователей работать в праздники из-за ошибок в коде.

← На главную