Разрабатывая некий функционал в 1С, бывает, необходимо посчитать количество рабочих дней после какой-то даты.
В этой статье примеры кода и запросы в которых считается количество рабочих дней:
Код, при вычислении определяет только по дню недели, викидывая выходные. Праздники не учитывает!
Код 1C v 8.х Функция РабочихДнейСДаты(НачДата,КолвоДней) Экспорт
Перем РабочихДней, ОбычныхДней, ДеньНедели;
РабочихДней = 0; ОбычныхДней = 0;
Пока РабочихДней < Число(КолвоДней) Цикл
ОбычныхДней = ОбычныхДней+ 1;
// определим день недели
ДеньНедели=ДеньНедели(НачДата+(ОбычныхДней*86400));
// если не выходной, то прошел еще один рабочий день
Если ДеньНедели < 6 Тогда
РабочихДней=РабочихДней+1;
КонецЕсли;
КонецЦикла;
Возврат (НачДата + (РабочихДней*86400));
КонецФункции
// Пример использования
ТриДняОтОбработки = РабочихДнейСДаты(нДатаОбработки,3);
Если РабочаяДата>ТриДняОтОбработки Тогда
Предупреждение("Прошло больше 3-х дней после обработки заказа. Цены не актуальны!
|Отправьте заказ на новую обработку! ");
Иначе
// ... неки код
КонецЕсли;
В запросе, с использованием производственного календаря и учетом всех праздников:
Код 1C v 8.х ВЫБРАТЬ
РегламентированныйПроизводственныйКалендарь.ДатаКалендаря КАК Дата
ПОМЕСТИТЬ Даты
ИЗ
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
ГДЕ
РегламентированныйПроизводственныйКалендарь.ДатаКалендаря В(&ВходящиеДаты)
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Даты.Дата,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ РегламентированныйПроизводственныйКалендарь.ДатаКалендаря) КАК КоличествоРабочихДней,
МАКСИМУМ(РегламентированныйПроизводственныйКалендарь.ДатаКалендаря) КАК ДатаКалендаря,
РегламентированныйПроизводственныйКалендарь1.ДатаКалендаря КАК ДатаКалендаряДляГруппировки
ИЗ
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Даты КАК Даты
ПО (Даты.Дата <= РегламентированныйПроизводственныйКалендарь.ДатаКалендаря)
И (ДОБАВИТЬКДАТЕ(Даты.Дата, ДЕНЬ,ГлубинаДней) > РегламентированныйПроизводственныйКалендарь.ДатаКалендаря)
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь1
ПО РегламентированныйПроизводственныйКалендарь.ДатаКалендаря <= РегламентированныйПроизводственныйКалендарь1.ДатаКалендаря
ГДЕ
(РегламентированныйПроизводственныйКалендарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный)
ИЛИ РегламентированныйПроизводственныйКалендарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий))
СГРУППИРОВАТЬ ПО
РегламентированныйПроизводственныйКалендарь1.ДатаКалендаря,
Даты.Дата
ИМЕЮЩИЕ
МАКСИМУМ(РегламентированныйПроизводственныйКалендарь.ДатаКалендаря) = РегламентированныйПроизводственныйКалендарь1.ДатаКалендаря
И КОЛИЧЕСТВО(РАЗЛИЧНЫЕ РегламентированныйПроизводственныйКалендарь.ДатаКалендаря) =РабочихДней
Еще один вариант, в котором допустим, что:
1) Регистр сведений Календарь имеет структуру (Измерения={ДатаКалендаря}, Ресурсы={ВидДня}), а перечисление ВидыДня задано как {Рабочий, Предпразничный} и праздничные дни в календаре отсутствуют.
2) В документе Реализация заданы поля Дата и ОтсрочкаДней. Тогда:
Код 1C v 8.х Выбрать
Р.Ссылка, Р.Дата,
минимум(isnull(К.ДатаКалендаря, добавитькдате(Р.Дата, день, Р.ОтсрочкаДней))) как ДатаКредита
из Документ.Реализация как Р
левое соединение РегистрСведений.Календарь как К
по добавитькдате(Р.Дата, день, Р.ОтсрочкаДней) <= К.ДатаКалендаря
сгруппировать по
Р.Ссылка, Р.Дата
Собственно, если календарь содержит и праздничные дни, то можно добавить секцию ГДЕ, и там отобрать только рабочие дни. В секции ГДЕ можно отобрать и интересующий календарь, если ведется несколько календарей.
В данной статье описаны функции которые вы можете использовать в ЗУП для получения количества рабочих дней по графику работы сотрудника или по производственному календарю
Код 1C v 8.х // Функции получения количества рабочих дней по графику работы сотрудника ил по производственному календарю
Функция КоличествоРабочихДнейПоГрафикуРаботы(ДатаН, ДатаК, ГрафикРаботы)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ГрафикиРаботыПоВидамВремени.ГрафикРаботы,
| ГрафикиРаботыПоВидамВремени.ВидУчетаВремени,
| СУММА(ГрафикиРаботыПоВидамВремени.ОсновноеЗначение) КАК ОсновноеЗначение,
| СУММА(ГрафикиРаботыПоВидамВремени.ДополнительноеЗначение) КАК ДополнительноеЗначение,
| СУММА(ГрафикиРаботыПоВидамВремени.ОсновноеЗначениеНорма) КАК ОсновноеЗначениеНорма,
| СУММА(ГрафикиРаботыПоВидамВремени.ДополнительноеЗначениеНорма) КАК ДополнительноеЗначениеНорма
|ИЗ
| РегистрСведений.ГрафикиРаботыПоВидамВремени КАК ГрафикиРаботыПоВидамВремени
|ГДЕ
| ГрафикиРаботыПоВидамВремени.ГрафикРаботы = &ГрафикРаботы
| И ГрафикиРаботыПоВидамВремени.Дата МЕЖДУ &ДатаН И &ДатаК
| И ГрафикиРаботыПоВидамВремени.ВидУчетаВремени = &ВидУчетаВремени
|
|СГРУППИРОВАТЬ ПО
| ГрафикиРаботыПоВидамВремени.ГрафикРаботы,
| ГрафикиРаботыПоВидамВремени.ВидУчетаВремени";
Запрос.УстановитьПараметр("ГрафикРаботы", ГрафикРаботы);
Запрос.УстановитьПараметр("ДатаК", ДатаК);
Запрос.УстановитьПараметр("ДатаН", ДатаН);
Запрос.УстановитьПараметр("ВидУчетаВремени", Перечисления.ВидыУчетаВремени.ПоДням);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ОсновноеЗначение = Выборка.ОсновноеЗначение;
Иначе
ОбщегоНазначенияЗК.СообщитьОбОшибке("Проверьте заполнение графика!");
ОсновноеЗначение = 0;
КонецЕсли;
Возврат ОсновноеЗначение;
КонецФункции
Функция КоличествоРабочихДнейПоПроизвКаленд(ДатаН, ДатаК)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СУММА(РегламентированныйПроизводственныйКалендарь.КалендарныеДни) КАК КоличествоДней,
| СУММА(РегламентированныйПроизводственныйКалендарь.Пятидневка) КАК Пятидневка,
| СУММА(РегламентированныйПроизводственныйКалендарь.Шестидневка) КАК Шестидневка
|ИЗ
| РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
|ГДЕ
| РегламентированныйПроизводственныйКалендарь.ДатаКалендаря >= &ДатаН
| И РегламентированныйПроизводственныйКалендарь.ДатаКалендаря <= &ДатаК";
Запрос.УстановитьПараметр("ДатаК", ДатаК);
Запрос.УстановитьПараметр("ДатаН", ДатаН);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ОсновноеЗначение = Выборка.Пятидневка;
Иначе
ОбщегоНазначенияЗК.СообщитьОбОшибке("Проверьте заполнение графика!");
ОсновноеЗначение = 0;
КонецЕсли;
Возврат ОсновноеЗначение;
КонецФункции
Код 1C v 8.х // Отбирать нужно за 1 месяц
// Выводит: Сотрудник, Организация, Норма в часах, норма в днях
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НАЧАЛОПЕРИОДА(Норма.ДатаКалендаря, МЕСЯЦ) КАК ПериодДействия,
| СотрудникиОрганизаций.Ссылка КАК Сотрудник,
| СотрудникиОрганизаций.ОбособленноеПодразделение КАК Организация,
| СУММА(ВЫБОР
| КОГДА Норма.ДатаКалендаря >= СотрудникиОрганизаций.ДатаПриемаНаРаботу
| И Норма.ДатаКалендаря <= СотрудникиОрганизаций.ДатаУвольнения
| ИЛИ Норма.ДатаКалендаря >= СотрудникиОрганизаций.ДатаПриемаНаРаботу
| И СотрудникиОрганизаций.ДатаУвольнения = ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)
| ТОГДА Норма.НормаВЧасах
| ИНАЧЕ 0
| КОНЕЦ) КАК НормаЧасов,
| СУММА(ВЫБОР
| КОГДА Норма.ДатаКалендаря >= СотрудникиОрганизаций.ДатаПриемаНаРаботу
| И Норма.ДатаКалендаря <= СотрудникиОрганизаций.ДатаУвольнения
| ИЛИ Норма.ДатаКалендаря >= СотрудникиОрганизаций.ДатаПриемаНаРаботу
| И СотрудникиОрганизаций.ДатаУвольнения = ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)
| ТОГДА Норма.НормаВДнях
| ИНАЧЕ 0
| КОНЕЦ) КАК НормаДней
|ИЗ
| (ВЫБРАТЬ
| СУММА(ВЫБОР
| КОГДА Норма.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
| ТОГДА 8
| ИНАЧЕ ВЫБОР
| КОГДА Норма.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный)
| ТОГДА 7
| ИНАЧЕ 0
| КОНЕЦ
| КОНЕЦ) КАК НормаВЧасах,
| Норма.ДатаКалендаря КАК ДатаКалендаря,
| ВЫБОР
| КОГДА Норма.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
| ТОГДА 1
| ИНАЧЕ ВЫБОР
| КОГДА Норма.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный)
| ТОГДА 1
| ИНАЧЕ 0
| КОНЕЦ
| КОНЕЦ КАК НормаВДнях
| ИЗ
| РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Норма
| ГДЕ
| Норма.ДатаКалендаря МЕЖДУ &НачалоПериода И &КонецПериода
|
| СГРУППИРОВАТЬ ПО
| Норма.ДатаКалендаря,
| ВЫБОР
| КОГДА Норма.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
| ТОГДА 1
| ИНАЧЕ ВЫБОР
| КОГДА Норма.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный)
| ТОГДА 1
| ИНАЧЕ 0
| КОНЕЦ
| КОНЕЦ) КАК Норма,
| Справочник.СотрудникиОрганизаций КАК СотрудникиОрганизаций
|
|СГРУППИРОВАТЬ ПО
| НАЧАЛОПЕРИОДА(Норма.ДатаКалендаря, МЕСЯЦ),
| СотрудникиОрганизаций.Ссылка,
| СотрудникиОрганизаций.ОбособленноеПодразделение";
Запрос.УстановитьПараметр("КонецПериода", Дата("31.05.2012 0:00:00"));
Запрос.УстановитьПараметр("НачалоПериода", Дата("01.05.2012 0:00:00"));
Результат = Запрос.Выполнить();
Выборка = Результат.Выгрузить();
Для каждого СтрокаТЗ Из Выборка Цикл
КонецЦикла;