К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как создать календарь в 1С конфигураторе

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

Календарь в 1С — это не одиночный объект, а связка метаданных: справочник с перечнем графиков, регистр сведений с датами и типами дней, а также программный код, который по этим данным считает рабочие и выходные дни. Такая конструкция используется в типовых конфигурациях (например, производственный календарь в ЗУП и Бухгалтерии), и её можно повторить в собственной разработке.

Прежде чем создавать объекты, определите задачу: нужен ли просто список праздничных дней, полноценный график работы сотрудников или расчёт сроков по рабочим дням. От этого зависит структура хранения. Для простого случая достаточно регистра сведений «Дата — вид дня», для графиков сотрудников понадобится дополнительный справочник и измерение в регистре.

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

Выбор структуры хранения календаря

В 1С нет готового объекта метаданных «Календарь», поэтому разработчик собирает его из стандартных строительных блоков. Классическая схема, применённая в типовых решениях, включает три элемента: перечисление «ВидыДнейКалендаря» (рабочий, выходной, праздничный, предпраздничный), справочник «Календари» (или «ГрафикиРаботыСотрудников») и регистр сведений, где каждая запись связывает дату, календарь и вид дня.

Альтернативный подход — хранить в регистре не вид дня, а числовой ресурс «КоличествоДней»: 1 для рабочего дня и 0 для нерабочего. Тогда количество рабочих дней за произвольный период вычисляется одним запросом с итогом, без перебора дат в цикле. Именно этот вариант рекомендуется для расчётных задач, потому что он быстрее и проще в поддержке.

Варианты хранения календаря

Регистр сведений «Дата — вид дня»

Наглядно, удобно для отображения пользователю, но расчёт рабочих дней требует дополнительной логики.

Регистр сведений с ресурсом 0/1

Оптимально для расчётов: сумма ресурса за период сразу даёт число рабочих дней.

Табличная часть справочника

Просто для одного календаря, но плохо масштабируется и неудобна для запросов по периодам.

Создание перечисления видов дней

Откройте конфигуратор, в дереве метаданных найдите ветку «Перечисления» и добавьте новый объект, например «ВидыДнейПроизводственногоКалендаря». На закладке «Данные» добавьте значения: Рабочий, Суббота, Воскресенье, Праздничный, Предпраздничный. Имена значений будут использоваться в коде, поэтому давайте им осмысленные идентификаторы без пробелов.

Если планируете хранить числовой ресурс 0/1 вместо вида дня, перечисление всё равно полезно — как второй ресурс или как служебные данные для отображения. В простейшей конфигурации без него можно обойтись, но в расчётах отпусков и больничных различать праздничные дни обычно требуется.

Создание справочника календарей

Добавьте справочник «Календари» с иерархией не требуется, достаточно стандартных реквизитов «Код» и «Наименование». В него будут занесены записи вида «Основной производственный календарь», «Пятидневка», «Шестидневка». Если ведёте учёт по нескольким странам или регионам, добавьте реквизит «Регион» или «Страна» для разделения праздников.

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

Создание регистра сведений с датами календаря

Это ключевой объект. Добавьте регистр сведений «ДанныеКалендаря» с режимом «Непериодический», независимый. В измерения включите «Дата» (тип «Дата», состав — дата) и «Календарь» (ссылка на созданный справочник). В ресурсы добавьте «ВидДня» (ссылка на перечисление) и при необходимости «РабочийДень» (число 1.0).

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

Установите для измерения «Дата» индексирование — оно включено по умолчанию для измерений, но проверьте это после изменений. Запросы к календарю почти всегда идут с отбором по диапазону дат, и без индекса на больших объёмах они замедлятся.

Порядок создания объектов
  1. 1
    Создайте перечисление «ВидыДнейКалендаря» со значениями Рабочий, Выходной, Праздничный.
  2. 2
    Добавьте справочник «Календари» и заведите в нём хотя бы одну запись.
  3. 3
    Создайте независимый регистр сведений с измерениями «Дата» и «Календарь», ресурсом «ВидДня».
  4. 4
    Обновите конфигурацию базы данных (F7) и убедитесь, что реструктуризация прошла без ошибок.
  5. 5
    Заполните регистр данными вручную или обработкой.

Заполнение календаря данными

Ручное заполнение годового календаря — около 365 записей на каждый график, поэтому практичнее написать простую обработку. Логика такая: цикл по датам года, определение дня недели функцией ДеньНедели(), запись в регистр субботы и воскресенья как выходных, остальных дней как рабочих, затем ручная корректировка праздников и переносов.

bsl
Процедура ЗаполнитьГод(Год, Календарь) Экспорт
	ТекДата = Дата(Год, 1, 1);
	Пока Год(ТекДата) = Год Цикл
		Менеджер = РегистрыСведений.ДанныеКалендаря.СоздатьМенеджерЗаписи();
		Менеджер.Дата = ТекДата;
		Менеджер.Календарь = Календарь;
		ДеньНед = ДеньНедели(ТекДата);
		Если ДеньНед = 6 Или ДеньНед = 7 Тогда
			Менеджер.ВидДня = Перечисления.ВидыДнейКалендаря.Выходной;
		Иначе
			Менеджер.ВидДня = Перечисления.ВидыДнейКалендаря.Рабочий;
		КонецЕсли;
		Менеджер.Записать();
		ТекДата = ТекДата + 86400;
	КонецЦикла;
КонецПроцедуры

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

Расчёт рабочих дней запросом

Главная практическая задача календаря — ответить на вопрос «сколько рабочих дней между двумя датами» или «какая дата наступит через N рабочих дней». Первый вопрос решается запросом с итогом по числовому ресурсу:

bsl
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	ЕСТЬNULL(СУММА(ДанныеКалендаря.РабочийДень), 0) КАК РабочихДней
|ИЗ
|	РегистрСведений.ДанныеКалендаря КАК ДанныеКалендаря
|ГДЕ
|	ДанныеКалендаря.Календарь = &Календарь
|	И ДанныеКалендаря.Дата МЕЖДУ &Начало И &Конец";
Запрос.УстановитьПараметр("Календарь", Календарь);
Запрос.УстановитьПараметр("Начало", НачалоПериода);
Запрос.УстановитьПараметр("Конец", КонецПериода);
Результат = Запрос.Выполнить().Выгрузить();

Для задачи «прибавить N рабочих дней к дате» сделайте запрос, который выбирает даты с ресурсом 1 начиная с исходной даты, упорядоченные по возрастанию, с отбором «ПЕРВЫЕ N». Последняя дата выборки и будет искомой. Такой подход работает за один запрос и не требует цикла по дням.

Если в регистре хранится вид дня вместо числового ресурса, расчёт делается через КОЛИЧЕСТВО записей с условием ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейКалендаря.Рабочий). Результат тот же, но запрос чуть тяжелее и менее универсален.

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

Отображение календаря пользователю

Для визуального представления используйте поле календаря формы или табличный документ с раскраской по видам дней. Простой вариант — форма списка регистра сведений с условным оформлением: выходные и праздничные подсвечиваются цветом через настройки условного оформления динамического списка.

Если нужен привычный «месячный» вид, формируйте табличный документ программно: семь колонок по дням недели, строки — недели, заливка ячеек по виду дня из регистра. Это требует больше кода, но даёт пользователю привычную картинку и возможность печати.

Проверка результата и типичные ошибки

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

Контрольные точки

Как проверить результат

Число записей за год
Норма

Равно 365 или 366 для високосного года

Тревожный признак

Меньше — есть пропуски дат, расчёты занизят рабочие дни

Сумма рабочих дней за месяц
Норма

Совпадает с официальным производственным календарём

Тревожный признак

Расходится — не учтены праздники или переносы

Запрос по диапазону дат
Норма

Выполняется быстро, возвращает корректный итог

Тревожный признак

Медленно работает или возвращает NULL при пустом периоде без ЕСТЬNULL

Типичные ошибки
01
Заполнение только рабочих дней: невозможно отличить выходной от незаполненного периода, расчёты за будущие даты дают ноль.
02
Жёсткое зашивание праздников в код: после изменения переносов приходится править и перепроверять код вместо данных.
03
Отсутствие ЕСТЬNULL в запросе: при пустом результате сумма возвращает NULL, и сравнения в коде ведут себя неожиданно.
04
Хранение дат в табличной части справочника: запросы по периодам усложняются и замедляются.
05
Использование секунд в датах измерения: записи с временем дублируют день и ломают отборы по диапазону.

Частые вопросы

Можно ли обойтись без справочника календарей, если график один?

Да. Уберите измерение «Календарь» из регистра и оставьте только «Дату». Но если позже появится второй график, придётся добавлять измерение и заполнять его во всех существующих записях, поэтому при малейшем сомнении измерение лучше заложить сразу.

Как учесть переносы выходных дней?

После автозаполнения года скорректируйте записи вручную или второй обработкой: день, ставший рабочим по переносу, перезаписывается с видом «Рабочий», а день, ставший выходным, — с видом «Выходной». Храните список переносов в данных, а не в коде, чтобы обновлять его без изменения конфигурации.

Чем отличается производственный календарь от графика работы сотрудника?

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

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

Добавьте в регистр ресурс «Часы» и заполняйте его при записи: для предпраздничных дней — сокращённое значение, для выходных — ноль. Тогда сумма ресурса за период даст норму часов, что нужно для расчёта зарплаты и табеля.

Почему запрос к календарю работает медленно?

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

Можно ли загрузить готовый календарь из типовой конфигурации?

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

Итог

Что важно запомнить

Календарь в 1С строится из перечисления видов дней, справочника графиков и регистра сведений с измерением «Дата». Заполняйте регистр полностью, включая выходные, храните числовой ресурс для быстрых расчётов запросом, а праздники и переносы держите в данных, а не в коде. Перед массовым заполнением рабочей базы делайте копию.