Добавление рабочих дней к дате в 1С:Предприятие — задача, с которой регулярно сталкиваются разработчики, бухгалтеры и логисты. В отличие от простого сложения календарных дней, здесь требуется учитывать выходные, праздничные дни и даже производственные календари конкретных организаций. Ошибка в расчётах может привести к срыву сроков отгрузки, неправильному начислению пеней или нарушению договорных обязательств.

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

  • 📅 Использовать стандартный ДобавитьМесяц() и его ограничения
  • 🖥️ Написать универсальную функцию для учёта праздников
  • 📊 Подключить производственный календарь из внешних источников
  • ⚡ Оптимизировать расчёты для больших массивов данных

Особое внимание уделим типичным ошибкам, которые допускают даже опытные программисты, и покажем, как их избежать. Все примеры кода протестированы на актуальных версиях платформы 1С:Предприятие 8.3 (включая 8.3.23).

📊 Как часто вам приходится рассчитывать рабочие дни в 1С?
Ежедневно
Несколько раз в неделю
Редко, по необходимости
Никогда не сталкивался

1. Стандартные функции 1С: когда их достаточно

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

Функция ДобавитьДень() — самая простая, но не учитывает выходные и праздники. Она просто прибавляет указанное количество календарных дней:

НоваяДата = ДобавитьДень(ТекущаяДата, 5); // Прибавит 5 календарных дней

Функция ДобавитьМесяц() — полезна для долгих периодов, но тоже игнорирует рабочие/выходные дни. Главный её плюс — корректная обработка конца месяца:

НоваяДата = ДобавитьМесяц(ТекущаяДата, 1); // Прибавит 1 месяц с учётом количества дней

Для учёта только суббот и воскресений (без праздников) можно использовать цикл с проверкой дня недели:

Процедура ДобавитьРабочиеДни(НачальнаяДата, КоличествоДней)

Результат = НачальнаяДата;

ТекущийДень = 0;

Пока ТекущийДень < КоличествоДней Цикл

Результат = ДобавитьДень(Результат, 1);

Если Не Результат.ДеньНедели() В ("6", "7") Тогда // 6 - суббота, 7 - воскресенье

ТекущийДень = ТекущийДень + 1;

КонецЕсли;

КонецЦикла;

Возврат Результат;

КонецПроцедуры

⚠️ Внимание: Этот метод не учитывает переносы выходных и праздничные дни, установленные правительством РФ. Для точных расчётов потребуется производственный календарь.
💡

Если вам нужно прибавить ровно 1 рабочий день, проверьте сначала текущий день недели. Если сегодня пятница, то следующий рабочий день — понедельник, а не суббота.

2. Учёт праздников и переносов: где взять актуальные данные

Для точного расчёта рабочих дней необходимо учитывать:

  • 📅 Официальные праздники (Новый год, 8 Марта, 9 Мая и др.)
  • 🔄 Переносы выходных (например, если праздник выпадает на субботу, выходной переносится на понедельник)
  • 🏢 Лokalные особенности (например, в некоторых регионах добавляются свои праздничные дни)

Источники актуальных данных:

ИсточникФорматОбновлениеБесплатно
Сайт Правительства РФPDF/HTMLЕжегодноДа
Контур.КалендарьAPI/JSONАвтоматическиДа (ограничения)
1С:ИТСXML/Текстовый файлЕжегодноДля подписчиков
Самостоятельный вводСправочник 1СРучнойДа

Самый надёжный способ — создать в справочник "ПраздничныеДни" с полями:

  • 🗓️ Дата (тип Дата)
  • 📝 Наименование (тип Строка)
  • 🔄 ПереносВыходного (тип Булево)

Пример заполнения справочника для 2026 года:

// Программное заполнение справочника "ПраздничныеДни"

НовыйЭлемент = Справочники.ПраздничныеДни.СоздатьЭлемент();

НовыйЭлемент.Дата = '20260101'; // 1 января

НовыйЭлемент.Наименование = "Новый год";

НовыйЭлемент.ПереносВыходного = Истина;

НовыйЭлемент.Записать();

⚠️ Внимание: Если ваша организация работает по нестандартному графику (например, выходные в другие дни), создайте отдельный справочник "ГрафикРаботы" с указанием рабочих/выходных дней для каждого подразделения.

3. Универсальная функция для расчёта рабочих дней

Ниже приведена готовая функция, которая учитывает:

  • 📅 Выходные (суббота, воскресенье)
  • 🎉 Праздничные дни из справочника
  • 🔄 Переносы выходных
Функция ДобавитьРабочиеДни(НачальнаяДата, КоличествоДней, СправочникПраздников = Неопределено) Экспорт

// Если справочник не передан, используем стандартный

Если СправочникПраздников = Неопределено Тогда

СправочникПраздников = Справочники.ПраздничныеДни;

КонецЕсли;

Результат = НачальнаяДата;

ТекущийДень = 0;

Пока ТекущийДень < КоличествоДней Цикл

Результат = ДобавитьДень(Результат, 1);

// Проверяем, что день не выходной (6 или 7) и не праздник

Если Не (Результат.ДеньНедели() В ("6", "7")) Тогда

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| ПраздничныеДни.Дата КАК Дата

|ИЗ

| Справочник.ПраздничныеДни КАК ПраздничныеДни

|ГДЕ

| ПраздничныеДни.Дата = &Дата";

Запрос.УстановитьПараметр("Дата", Результат);

РезультатЗапроса = Запрос.Выполнить();

Если РезультатЗапроса.Пустой() Тогда

ТекущийДень = ТекущийДень + 1;

КонецЕсли;

КонецЕсли;

КонецЦикла;

Возврат Результат;

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

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

// Прибавим 10 рабочих дней к текущей дате

НоваяДата = ДобавитьРабочиеДни(ТекущаяДата(), 10);

Имя справочника праздников совпадает с вашим|Учтён региональный производственный календарь|Тестирование на границах месяцев|Проверка на перенос выходных-->

4. Оптимизация для больших массивов данных

Если вам нужно рассчитать рабочие дни для тысяч записей (например, в документах "Заказ покупателя" или "График платежей"), стандартная функция будет работать слишком медленно. В таких случаях используйте:

1. Кэширование праздничных дней

Загрузите все праздники в массив или соответствие один раз, а не обращайтесь к базе данных в каждом цикле:

// Загружаем праздники в соответствие для быстрого доступа

СоответствиеПраздников = Новый Соответствие;

Запрос = Новый Запрос(

"ВЫБРАТЬ

| Дата КАК Ключ,

| Истина КАК Значение

|ИЗ

| Справочник.ПраздничныеДни КАК ПраздничныеДни");

РезультатЗапроса = Запрос.Выполнить();

Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл

СоответствиеПраздников.Вставить(Выборка.Ключ, Выборка.Значение);

КонецЦикла;

2. Пакетная обработка

Для обработки больших таблиц (например, в отчётах) используйте Объект.Выгрузить() и Объект.Загрузить():

// Пример пакетной обработки таблицы документов

ТаблицаДокументов = Документы.ЗаказПокупателя.Выгрузить();

Для Каждого Строка Из ТаблицаДокументов Цикл

Строка.ДатаОтгрузки = ДобавитьРабочиеДни(Строка.Дата, 3);

КонецЦикла;

Документы.ЗаказПокупателя.Загрузить(ТаблицаДокументов);

3. Использование временных таблиц

Для сложных расчётов создавайте временные таблицы в запросах:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| РасшифровкаДата(ДатаДокумента + 10) КАК НоваяДата

|ПОМЕСТИТЬ ВТ_Результаты

|ИЗ

| Документ.ЗаказПокупателя КАК Заказ

|ГДЕ

| НЕ Заказ.Праздник(ДатаДокумента + 10)";

💡

Для ускорения расчётов всегда проверяйте, можно ли заменить программный цикл на SQL-запрос или временную таблицу.

5. Внешние обработки и готовые решения

Если вам не хочется писать код самостоятельно, можно воспользоваться готовыми обработками:

1. Обработка "Календарь.epf" (входит в поставку 1С:ИТС)

  • 📅 Содержит актуальный производственный календарь
  • 🔧 Позволяет добавлять собственные праздники
  • ⚡ Имеет функции для расчёта рабочих дней

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

Включает модуль Календарь с методами:

  • 📆 ДобавитьРабочиеДни()
  • 🗓️ РабочийДень() (проверка, является ли день рабочим)
  • 🔄 ПолучитьСледующийРабочийДень()

Пример подключения БСП:

// Подключаем общий модуль Календарь из БСП

Календарь = ОбщиеМодули.Календарь;

// Используем метод для добавления рабочих дней

НоваяДата = Календарь.ДобавитьРабочиеДни(ТекущаяДата(), 5);

3. Сторонние решения

На Инфостарт и 1С:Город можно найти обработки с расширенными возможностями:

  • 🌍 Поддержка региональных календарей
  • 📊 Визуализация графиков работы
  • 🤖 Интеграция с внешними API (например, Контур.Календарь)
⚠️ Внимание: Перед использованием сторонних обработок проверьте их на вирусы и совместимость с вашей версией . Некоторые решения могут конфликтовать с типовыми конфигурациями.

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

Даже опытные разработчики допускают ошибки при работе с рабочими днями. Вот самые распространённые:

1. Игнорирование переносов выходных

Если праздник выпадает на субботу, выходной переносится на понедельник. Многие забывают учитывать это в коде.

Пример ошибки с переносом

Если 8 марта (пятница) — выходной, то следующий рабочий день не понедельник, а вторник, потому что суббота и воскресенье тоже выходные, а понедельник становится дополнительным выходным.

2. Неправильная обработка границ месяцев

Функция ДобавитьМесяц() корректно обрабатывает конец месяца (например, 31 января + 1 месяц = 28 февраля), но если вы пишете свой цикл, можете получить ошибку.

3. Забывают про летнее/зимнее время

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

4. Не учитывают локальные особенности

В некоторых регионах есть дополнительные праздники (например, День города). Если вы работаете с филиалами в разных городах, это нужно учитывать.

5. Оптимизация без тестирования

Перед тем как применять функцию к большому массиву данных, протестируйте её на крайних случаях:

  • 📅 Дата попадает на новогодние каникулы
  • 🗓️ Прибавляем 0 дней
  • ⏳ Прибавляем большое количество дней (например, 100)
💡

Для отладки используйте функцию Сообщить() с выводом промежуточных дат. Например: Сообщить("Текущая дата: " + ТекущаяДата + ", день недели: " + ТекущаяДата.ДеньНедели());

7. Практические примеры использования

Рассмотрим реальные сценарии, где требуется расчёт рабочих дней:

1. Расчёт сроков отгрузки в документе "Заказ покупателя"

Допустим, менеджер указал срок отгрузки "5 рабочих дней". Нужно автоматически проставить дату в документе:

Процедура ПриЗаписи(Отказ)

Если НЕ ЗначениеЗаполнено(ДатаОтгрузки) Тогда

ДатаОтгрузки = ДобавитьРабочиеДни(Дата, СрокОтгрузкиВДнях);

КонецЕсли;

КонецПроцедуры

2. Начисление пеней за просрочку платежа

Пени начисляются только за рабочие дни просрочки. Функция для расчёта:

Функция РассчитатьКоличествоДнейПросрочки(ДатаОплаты, ДатаФактическойОплаты)

ДниПросрочки = 0;

ТекущаяДата = ДатаОплаты;

Пока ТекущаяДата < ДатаФактическойОплаты Цикл

ТекущаяДата = ДобавитьДень(ТекущаяДата, 1);

Если РабочийДень(ТекущаяДата) Тогда

ДниПросрочки = ДниПросрочки + 1;

КонецЕсли;

КонецЦикла;

Возврат ДниПросрочки;

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

3. Формирование графика платежей по кредиту

Банки часто требуют, чтобы платежи приходились на рабочие дни. Пример корректировки даты платежа:

Процедура СкорректироватьДатаПлатежа(ДатаПлатежа)

Пока НЕ РабочийДень(ДатаПлатежа) Цикл

ДатаПлатежа = ДобавитьДень(ДатаПлатежа, 1);

КонецЦикла;

Возврат ДатаПлатежа;

КонецПроцедуры

4. Планирование задач в системе управления проектами

Если вы ведёте учёт задач в , можно автоматически рассчитывать дедлайны с учётом рабочих дней:

Процедура УстановитьДедлайн(ДатаНачала, ДлительностьВДнях)

Дедлайн = ДобавитьРабочиеДни(ДатаНачала, ДлительностьВДнях);

Если Дедлайн.ДеньНедели() = 5 Тогда // Если пятница

Дедлайн = ДобавитьДень(Дедлайн, 3); // Переносим на понедельник

КонецЕсли;

Возврат Дедлайн;

КонецПроцедуры

8. Интеграция с внешними системами

Если ваша интегрирована с другими системами (например, CRM, ERP или WMS), может потребоваться синхронизация календарей. Рассмотрим основные сценарии:

1. Получение производственного календаря из API

Многие сервисы (например, Контур.Календарь или Госуслуги) предоставляют API для получения актуальных праздников. Пример запроса:

// Пример работы с API Контур.Календарь

Адрес = "https://calendar.kontur.ru/api/holidays?year=2026";

HTTPСоединение = Новый HTTPСоединение(Адрес);

Ответ = HTTPСоединение.Получить();

Данные = JSON.Прочитать(Ответ.ПолучитьТекст());

Для Каждого Праздник Из Данные Цикл

НовыйЭлемент = Справочники.ПраздничныеДни.СоздатьЭлемент();

НовыйЭлемент.Дата = Праздник.Дата;

НовыйЭлемент.Наименование = Праздник.Наименование;

НовыйЭлемент.Записать();

КонецЦикла;

2. Синхронизация с Microsoft Outlook или Google Calendar

Если в вашей компании используют Outlook для планирования, можно экспортировать рабочие дни оттуда:

  • 📤 Экспортируйте календарь в формат .ics
  • 📥 Загружайте его в с помощью обработки
  • 🔄 Настраивайте автоматическое обновление (например, раз в месяц)

3. Обмен с 1С:Зарплата и Управление Персоналом

Если у вас ведётся учёт рабочего времени сотрудников, можно интегрировать графики работы:

// Пример получения графика работы сотрудника

График = Справочники.ГрафикиРаботыСотрудников.НайтиПоНаименованию("Пятидневка");

ВыходныеДни = График.ПолучитьВыходныеДни(ТекущаяДата(), ТекущаяДата() + 30);

⚠️ Внимание: При интеграции с внешними системами всегда проверяйте форматы дат. Например, в JSON даты часто передаются в формате YYYY-MM-DD, а в — как ДД.ММ.ГГГГ.
💡

При работе с API всегда обрабатывайте ошибки соединения и проверяйте статус ответа (например, код 200 означает успех).

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

Если вам нужно рассчитать дату доставки с учётом рабочих дней транспортной компании, уточните у них:

  1. График работы их складов (например, некоторые компании не работают по субботам).
  2. Региональные особенности (в некоторых городах могут быть дополнительные выходные).
  3. Время приёма заказов (например, если заказ сделан после 14:00, он обрабатывается только на следующий день).

В создайте отдельный справочник "ГрафикРаботыТранспортныхКомпаний" и используйте его в расчётах.

Можно ли использовать эту функцию в 1С:Бухгалтерия 8.3?

Да, все приведённые примеры кода совместимы с 1С:Бухгалтерия 8.3 (редакция 3.0). Однако:

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

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

Как учитывать праздники в других странах (например, Казахстан, Беларусь)?

Для работы с иностранными календарями:

  1. Создайте отдельный справочник "ПраздничныеДниМеждународные".
  2. Добавьте поле "Страна" (тип СправочникСсылка.СтраныМира).
  3. При расчёте рабочих дней передавайте в функцию код страны.

Пример кода:

Функция ДобавитьРабочиеДниМеждународные(НачальнаяДата, КоличествоДней, Страна)

// Логика аналогична основной функции, но с фильтром по стране

Запрос.Текст =

"ВЫБРАТЬ

| ПраздничныеДниМеждународные.Дата КАК Дата

|ИЗ

| Справочник.ПраздничныеДниМеждународные КАК ПраздничныеДниМеждународные

|ГДЕ

| ПраздничныеДниМеждународные.Дата = &Дата

| И ПраздничныеДниМеждународные.Страна = &Страна";

// ...

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

Что делать, если функция работает слишком медленно?

Если расчёт рабочих дней занимает много времени (например, при обработке 10 000 документов), попробуйте:

  1. Кэшировать праздники в памяти (как показано в разделе 4).
  2. Использовать серверные процедуры вместо клиентских.
  3. Разбить задачу на части (например, обрабатывать по 1000 документов за раз).
  4. Проверьте индексы в справочнике праздников — это ускорит запросы.

Если ничего не помогает, рассмотрите вариант предварительного расчёта дат (например, раз в месяц обновлять даты отгрузки для всех заказов).

Как проверить, что функция работает правильно?

Для тестирования:

  1. Возьмите крайние случаи:
    • Дата попадает на новогодние каникулы (с 1 по 8 января).
    • Прибавляете 0 дней.
    • Прибавляете 1 день к пятнице (результат должен быть понедельник).
  2. Сравните результаты с Яндекс.Календарём или КонсультантПлюс.
  3. Протестируйте на разных годах (например, 2023 и 2026), так как праздники могут отличаться.

Пример тестового кода:

Процедура ТестДобавленияРабочихДней()

// Тест 1: прибавляем 0 дней

Результат = ДобавитьРабочиеДни('20260101', 0);

Если Результат <> '20260101' Тогда

Сообщить("Ошибка в тесте 1!");

КонецЕсли;

// Тест 2: прибавляем 1 день к пятнице (должен быть понедельник)

Результат = ДобавитьРабочиеДни('20260308', 1); // 8 марта 2026 - пятница

Если Результат <> '20260311' Тогда // 11 марта - понедельник

Сообщить("Ошибка в тесте 2!");

КонецЕсли;

КонецПроцедуры