Опубликовано: 18.08.2022

Работа с календарями и праздниками

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

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

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

Контекст работы с календарями и праздниками

Доступ к атрибутам и методам календарей может осуществляться через переменную, содержащую ссылку на объект типа "Календарь", созданный с помощью системной функции СоздатьОбъект(), в которой в значении параметра использовано ключевое слово «Календарь» (англоязычный синоним — «Calendar»). Например:

Кал = СоздатьОбъект("Календарь.Служащие");

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

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

Календари.Служащие.Дней(ТекДата, ТекДата + 5);

Объекты типа "Календарь" являются сохраняемыми, то есть реквизиты справочников, документов, журналов расчёта могут иметь тип "Календарь" и хранить ссылки на объекты этого типа.

Пример:

Процедура ПровестиРасчет()
   // ВнСовместитель — реквизит журнала расчетов
   // Категории — периодический реквизит справочника ВнутренниеСовместители
   // Календарь — реквизит справочника Категории
   Календ = ВнСовместитель.Категория.Получить(ДатаОкончания).Календарь;
   // размер оклада
   Оклад = ВнСовместитель.Оклад.Получить(ДатаОкончания) *
                   ВнСовместитель.Ставка.Получить(ДатаОкончания);
   Дней = Календ.Дней(ДатаНачала, ДатаОкончания);
   ВсегоДней = Календ.Дней(НачалоПериодаПоДате(ДатаНачала),
                   КонецПериодаПоДате(ДатаНачала));
   Если ВсегоДней > 0 Тогда
      Если Документ.Вид() = "НачалоМесяца" Тогда
         Результат = Окр(Оклад * Дней/ВсегоДней);
      Иначе
         Результат = -Окр(Оклад * Дней/ВсегоДней);
      КонецЕсли;
   Иначе
      Результат = 0;
      Сообщить("Неправильно указан календарь (" + Объект.Наименование + ")");
      Сообщить("Возможно, не задана категория работника");
   КонецЕсли;
КонецПроцедуры

Доступ же к атрибутам и методам праздников осуществляется только через переменную, содержащую ссылку на объект "Праздники", созданный с помощью системной функции СоздатьОбъект(), в которой в значении параметра использовано ключевое слово «Праздники» (англоязычный синоним — «Holidays»). Например:

Празд = СоздатьОбъект("Праздники");

Атрибуты и методы глобального объекта Календари

Задать значение календаря конкретного вида, как я уже сказал ранее, позволяет атрибут <ИмяКалендаря>. В тексте программного модуля в качестве имени атрибута используется название конкретного вида календаря, как он назван в Конфигураторе.

Пример:

Календари.Служащие.Дней(ТекДата, ТекДата + 5);

Получить значение объекта конкретного вида календаря по имени позволяет также метод ПолучитьАтрибут() (англоязычный синоним — GetAttrib()) глобального объекта Календари.

Синтаксис:

Календари.ПолучитьАтрибут(<ИмяКалендаря>)

где <ИмяКалендаря> — строковое выражение, содержащее имя конкретного вида календаря, как оно задано в Конфигураторе.

Пример:

Календари.ПолучитьАтрибут("Служащие").Дней(ТекДата, ТекДата + 5);

Общие атрибуты календарей и праздников

Получить дату текущей строки календаря или праздника (то есть строки, на которой позиционирована выборка) позволяет доступный только для чтения атрибут Дата (англоязычный синоним — Date).

Получить значение текущей строки календаря или праздника (то есть строки, на которой позиционирована выборка) позволяет атрибут Значение (англоязычный синоним — Value). Значение данного атрибута представляет собой число с двумя знаками после запятой.

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

Общие методы календарей и праздников

Получить значение атрибута по имени позволяет метод ПолучитьАтрибут() (англоязычный синоним — GetAttrib()). Возвращаемым значением метода будет значение атрибута, имя которого указано в параметре.

Синтаксис:

ПолучитьАтрибут(<ИмяАтрибута>)

где <ИмяАтрибута> — строковое выражение, содержащее имя атрибута. Доступные имена атрибутов — "Дата" и "Значение".

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

// Календарь служащих
Календ = СоздатьОбъект("Календарь.Служащие");
Календ.ВыбратьДаты(ДатаНачала, ДатаОкончания);
Пока Календ.СледующаяДата() = 1 Цикл
   Сообщить("" + Календ.ПолучитьАтрибут("Дата") + "; ");
    . . .
КонецЦикла;

Установить значение атрибута по имени позволяет метод УстановитьАтрибут() (англоязычный синоним — SetAttrib()).

Синтаксис:

УстановитьАтрибут(<ИмяАтрибута>, <Значение>)

где

  • <ИмяАтрибута> — строковое выражение, содержащее имя атрибута. Доступные имена атрибутов — "Дата" и "Значение";
  • <Значение> — выражение, содержащее устанавливаемое значение атрибута.

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

// Календарь служащих
Календ = СоздатьОбъект("Календарь.Служащие");
Календ.ВыбратьДаты(ДатаНачала, ДатаОкончания);
Пока Календ.СледующаяДата() = 1 Цикл
   Календ.УстановитьАтрибут("Значение", 1);
    . . .
КонецЦикла;

Методы календарей

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

Выполнить автозаполнение календаря в заданном периоде позволяет метод Автозаполнение() (англоязычный синоним — Autolayout()). При этом старые данные (в том числе «ручные» исправления) в указанном периоде пропадают. В зависимости от результата работы метод возвращает число: 1 — получилось; 0 — не получилось.

Синтаксис метода:

Автозаполнение(<ДатаНачала>, <ДатаОкончания>)

где

  • <ДатаНачала> — дата начала периода автозаполнения;
  • <ДатаОкончания> — дата окончания периода автозаполнения.

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

// Календарь служащих
Календ = СоздатьОбъект("Календарь.Служащие");
Календ.УчитыватьПраздники(1);
Результат = Календ.Автозаполнение(ДатаНачала, ДатаОкончания);

Установить флага учёта праздников при автозаполнении позволяет метод УчитыватьПраздники() (англоязычный синоним — UseHolidays()). Возвращаемым значением метода является текущая установка флага (1 — учитываются праздники; 0 — не учитываются праздники) на момент предшествующий вызову метода.

Синтаксис метода:

УчитыватьПраздники(<Флаг>)

где <Флаг> — число: 1 — учитывать праздники при автозаполнении; 0 — не учитывать праздники при автозаполнении. Параметр является необязательным.

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

// Календарь служащих
Календ = СоздатьОбъект("Календарь.Служащие");
Календ.УчитыватьПраздники(1);
Результат = Календ.Автозаполнение(ДатаНачала, ДатаОкончания);

Примечание: В «ручном» режиме автозаполнение календаря осуществляется с помощью кнопки «Автозаполнение», а флаг учёта праздников устанавливается с помощью соответствующей «галочки»:

Календарь

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

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

Синтаксис метода:

ВыбратьДаты(<ДатаНачала>, <ДатаОкончания>)

где

  • <ДатаНачала> — дата начала периода выборки;
  • <ДатаОкончания> — дата окончания периода выборки.

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

// Календарь служащих
Календ = СоздатьОбъект("Календарь.Служащие");
Календ.ВыбратьДаты(ДатаНачала, ДатаОкончания);
Пока Календ.СледующаяДата() = 1 Цикл
    . . .
КонецЦикла;

Выбрать следующий день календаря из выборки, открытой методом ВыбратьДаты(), позволяет метод СледующаяДата() (англоязычный синоним — NextDate()). Возвращаемым значением метода является число 1, если получена очередная запись, или 0, если не обнаружено очередной записи (то есть достигнут конец выборки). Параметров у этого метода нет.

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

// Календарь служащих
Календ = СоздатьОбъект("Календарь.Служащие");
Календ.ВыбратьДаты(ДатаНачала, ДатаОкончания);
Пока Календ.СледующаяДата() = 1 Цикл
    . . .
КонецЦикла;

Проверка выбора календаря

Календарь в рамках описываемого встроенного языка — это сохраняемый агрегатный тип данных, то есть объекты этого типа могут сохраняться в информационной базе. Например, реквизиты справочника, документа или журнала расчётов, могут иметь тип "Календарь" и, следовательно, хранить ссылки на конкретные календари. При этом часто необходимо иметь возможность определить выбрано ли конкретное значение для реквизита (например, справочника или документа) этого типа. Метод Выбран() (англоязычный синоним — Selected()) предназначен для определения, не является ли «пустым» значение переменной или реквизита типа "Календарь". Метод возвращает 1, если конкретный календарь выбран; 0 в противном случае. Параметров у метода нет.

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

// реквизит справочника Календ имеет тип "Календарь"
Спр = СоздатьОбъект("Справочник.Категории");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
   Если Спр.Календ.Выбран() = 0 Тогда
      Сообщить("Не указан конкретный календарь!");
   КонецЕсли;
КонецЦикла;

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

Для определения даты, отстоящей от заданной даты на известное количество дней, предназначен метод ПолучитьДату() (англоязычный синоним — GetDate()). В отличие от простого прибавления числа к дате, результатом которого является дата, смещенная на заданное количество дней, данный метод производит определение итоговой даты, пропуская «нерабочие» дни календаря, для которых задано нулевое значение.

Синтаксис метода:

ПолучитьДату(<ДатаОтсчета>, <Количество>)

где

  • <ДатаОтсчета> — дата, от которой будут отсчитываться дни;
  • <Количество> — количество отсчитываемых дней.

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

Процедура ПровестиДокумент()
   Если Число(Окончание) = 0 Тогда
      // календарь
      Календ = Сотрудник.Категория.Получить(Начало).Календарь;
      // при расчете отпуска, запишем дату его окончания
      Календ = СоздатъОбъект("Календарь.Отпуск");
      Окончание = Календ.ПолучитьДату(Начало, КоличДней);
   КонецЕсли;
   Если Расчет <> ВидРасчета.ОтпускПоУходуЗаРебенком Тогда
      Если Окончание > ЖрнЗарплата.КонецТекущегоПериода() Тогда
         РасчетВперед(ГруппаРасчетов.ПересчДляОтпуска, Сотрудник, ТекущийДокумент());
      КонецЕсли;
      ЖрнЗарплата.ВвестиРасчет(Сотрудник, Расчет, Начало, Окончание, 0);
   Иначе
      ЖрнЗарплата.ВвестиРасчет(Сотрудник, Расчет,
             Макс(Начало, ЖрнЗарплата.НачалоТекущегоПериода()),
             Мин(Окончание, ЖрнЗарплата.КонецТекущегоПериода()), 0);
      Зарегистрировать(Контекст, ТекущийДокумент());
   КонецЕсли;
КонецПроцедуры

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

Синтаксис метода:

Дней(<ДатаНачала>, <ДатаОкончания>)

где

  • <ДатаНачала> — дата начала периода, в котором определяется количество дней;
  • <ДатаОкончания> — дата окончания периода, в котором определяется количество дней. Если значение <ДатаОкончания> меньше, чем значение <ДатаНачала>, будет выведено сообщение об ошибке.

Примечание: Значения <ДатаНачала> и <ДатаОкончания> включаются в рассматриваемый период.

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

// Расчет оплаты по окладу
// Календарь служащих
Календ = СоздатьОбъект("Календарь.Служащие");
// отработал...
Дни = Календ.Дней(ДатаНачала, ДатаОкончания);
// должен был бы работать...
Норма = Календ.Дней(НачалоПериодаПоДате(ДатаНачала), КонецПериодаПоДате(ДатаНачала));
// получим оклад сотрудника на дату начала
// действия данного расчета
Оклад = Объект.Оклад.Получить(ДатаНачала);
// результат
Результат = Дни * Оклад / Норма;

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

Синтаксис метода:

Часов(<ДатаНачала>, <ДатаОкончания>)

где

  • <ДатаНачала> — дата начала периода, в котором определяется сумма числовых значений, интерпретируемая как количество часов;
  • <ДатаОкончания> — дата окончания периода, в котором определяется сумма числовых значений, интерпретируемая как количество часов. Если значение <ДатаОкончания> меньше, чем значение <ДатаНачала>, будет выведено сообщение об ошибке.

Примечание: Значения <ДатаНачала> и <ДатаОкончания> включаются в рассматриваемый период.

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

// Расчет оплаты по часовому тарифу
// Календарь рабочих
Календ = СоздатьОбъект("Календарь.Рабочие");
// отработал...
Чс = Календ.Часов(ДатаНачала, ДатаОкончания);
// должен был бы работать...
Норма = Календ.Часов(НачалоПериодаПоДате(ДатаНачала), КонецПериодаПоДате(ДатаНачала));
// получим тариф сотрудника на дату начала действия данного расчета
Тариф = Объект.Тариф.Получить(ДатаНачала);
// результат
Результат = Чс * Тариф / Норма;

Методы праздников

Создать новую запись о «праздничном» дне на указанную дату позволяет метод Новый() (англоязычный синоним — New()). Синтаксис данного метода следующий:

Новый(<Дата>, <Значение>)

где

  • <Дата> — дата нового праздника;
  • <Значение> — положительное число с двумя знаками после запятой (не более 100). Поскольку объект "Праздники", как правило, используется для ввода выходных праздничных дней по календарям, то значение, как правило, задают равным нулю.

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

// Праздничные дни
Празд = СоздатьОбъект("Праздники");
Празд.Новый('01.05.99', 0);

Удалить существующую запись о «праздничном» дне позволяет метод Удалить() (англоязычный синоним — Delete()). Если строка с такой датой не найдена, то метод ничего не делает. Возвращаемого значения у метода нет.

Синтаксис метода:

Удалить(<Дата>)

где <Дата> — дата удаляемого праздника.

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

Празд = СоздатьОбъект("Праздники");
Празд.Удалить('01.05.99');

Открыть выборку записей праздников позволяет метод ВыбратьДаты() (англоязычный синоним — SelectDates()). При этом выбираются все элементы с даты начала по дату окончания включительно. Последующий переход от записи к записи осуществляется с помощью метода СледующаяДата(). Возвращаемым значением метода ВыбратьДаты() будет число 1, если выборка открыта и в ней есть хоть одна запись, или 0, если не обнаружено ни одной записи.

Синтаксис метода:

ВыбратьДаты(<ДатаНачала>, <ДатаОкончания>)

где

  • <ДатаНачала> — дата начала периода выборки;
  • <ДатаОкончания> — дата окончания периода выборки.

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

// Праздничные дни
Празд = СоздатьОбъект("Праздники");
Празд.ВыбратьДаты(ДатаНачала, ДатаОкончания);
Пока Празд.СледующаяДата() = 1 Цикл
    . . .
КонецЦикла;

Выбрать следующий день в порядке дат в выборке, открытой методом ВыбратьДаты(), позволяет метод СледующаяДата() (англоязычный синоним — NextDate()). Параметров у метода нет. Возвращаемым значением метода будет число 1, если получена очередная запись, или 0, если не обнаружено очередной записи (то есть достигнут конец выборки).

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

// Праздничные дни
Празд = СоздатьОбъект("Праздники");
Празд.ВыбратьДаты(ДатаНачала, ДатаОкончания);
Пока Празд.СледующаяДата() = 1 Цикл
    . . .
КонецЦикла;

Другие статьи по схожей тематике