Разность дат по календарю. Определяет количество дней, входящих в график, для указанного периода.
// Определяет количество дней, входящих в график, для указанного периода.
//
// Параметры:
// ГрафикРаботы - СправочникСсылка.Календари, СправочникСсылка.ПроизводственныеКалендари - график или
// производственный календарь, который необходимо использовать для расчета дней.
// ДатаНачала - Дата - дата начала периода.
// ДатаОкончания - Дата - дата окончания периода.
// ВызыватьИсключение - Булево - если Истина, вызвать исключение в случае незаполненного графика.
//
// Возвращаемое значение:
// Число - количество дней между датами начала и окончания.
// Если график ГрафикРаботы не заполнен, и ВызыватьИсключение = Ложь, возвращается Неопределено.
//
Функция РазностьДатПоКалендарю(Знач ГрафикРаботы, Знач ДатаНачала, Знач ДатаОкончания, ВызыватьИсключение = Истина) Экспорт
Если Не ЗначениеЗаполнено(ГрафикРаботы) Тогда
Если ВызыватьИсключение Тогда
ВызватьИсключение НСтр("ru = 'Не указан график работы или производственный календарь.'");
КонецЕсли;
Возврат Неопределено;
КонецЕсли;
ДатаНачала = НачалоДня(ДатаНачала);
ДатаОкончания = НачалоДня(ДатаОкончания);
ДатыГрафика = Новый Массив;
ДатыГрафика.Добавить(ДатаНачала);
Если Год(ДатаНачала) <> Год(ДатаОкончания) И КонецДня(ДатаНачала) <> КонецГода(ДатаНачала) Тогда
// Если даты разных годов, то добавляем «границы» годов.
Для НомерГода = Год(ДатаНачала) По Год(ДатаОкончания) - 1 Цикл
ДатыГрафика.Добавить(Дата(НомерГода, 12, 31));
КонецЦикла;
КонецЕсли;
ДатыГрафика.Добавить(ДатаОкончания);
// Формируем текст запроса временной таблицы, содержащей указанные даты.
ТекстЗапроса = "";
Для Каждого ДатаГрафика Из ДатыГрафика Цикл
Если ПустаяСтрока(ТекстЗапроса) Тогда
ШаблонОбъединения =
"ВЫБРАТЬ
| ДАТАВРЕМЯ(%1) КАК ДатаГрафика
|ПОМЕСТИТЬ ВТДатыГрафика
|";
Иначе
ШаблонОбъединения =
"ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| ДАТАВРЕМЯ(%1)";
КонецЕсли;
ТекстЗапроса = ТекстЗапроса + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОбъединения, Формат(ДатаГрафика, "ДФ='гггг, ММ, д'"));
КонецЦикла;
МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
Запрос.Выполнить();
// Готовим временные таблицы с исходными данными.
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| ДатыГрафика.ДатаГрафика
|ПОМЕСТИТЬ ВТРазличныеДатыГрафика
|ИЗ
| ВТДатыГрафика КАК ДатыГрафика
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| ГОД(ДатыГрафика.ДатаГрафика) КАК Год
|ПОМЕСТИТЬ ВТРазличныеГодыГрафика
|ИЗ
| ВТДатыГрафика КАК ДатыГрафика";
Запрос.Выполнить();
Если ТипЗнч(ГрафикРаботы) = Тип("СправочникСсылка.ПроизводственныеКалендари") Тогда
// По производственному календарю.
Запрос.Текст =
"ВЫБРАТЬ
| КалендарныеГрафики.Год,
| КалендарныеГрафики.Дата КАК ДатаГрафика,
| ВЫБОР
| КОГДА КалендарныеГрафики.ВидДня В (ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий), ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный))
| ТОГДА ИСТИНА
| ИНАЧЕ ЛОЖЬ
| КОНЕЦ КАК ДеньВключенВГрафик
|ПОМЕСТИТЬ ВТКалендарныеГрафики
|ИЗ
| РегистрСведений.ДанныеПроизводственногоКалендаря КАК КалендарныеГрафики
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТРазличныеГодыГрафика КАК ГодыГрафика
| ПО (ГодыГрафика.Год = КалендарныеГрафики.Год)
|ГДЕ
| КалендарныеГрафики.ПроизводственныйКалендарь = &ГрафикРаботы";
Запрос.УстановитьПараметр("ГрафикРаботы", ГрафикРаботы);
Запрос.Выполнить();
Иначе
// По графику работы
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГрафикиРаботы") Тогда
МодульГрафикиРаботы = ОбщегоНазначения.ОбщийМодуль("ГрафикиРаботы");
МодульГрафикиРаботы.СоздатьВТДанныеГрафика(МенеджерВременныхТаблиц, ГрафикРаботы);
КонецЕсли;
КонецЕсли;
Запрос.Текст =
"ВЫБРАТЬ
| ДатыГрафика.ДатаГрафика,
| КОЛИЧЕСТВО(ДниВключенныеВГрафик.ДатаГрафика) КАК КоличествоДнейВГрафикеСНачалаГода
|ПОМЕСТИТЬ ВТКоличествоДнейВключенныхВГрафик
|ИЗ
| ВТРазличныеДатыГрафика КАК ДатыГрафика
| ЛЕВОЕ СОЕДИНЕНИЕ ВТКалендарныеГрафики КАК ДниВключенныеВГрафик
| ПО (ДниВключенныеВГрафик.Год = ГОД(ДатыГрафика.ДатаГрафика))
| И (ДниВключенныеВГрафик.ДатаГрафика <= ДатыГрафика.ДатаГрафика)
| И (ДниВключенныеВГрафик.ДеньВключенВГрафик)
|
|СГРУППИРОВАТЬ ПО
| ДатыГрафика.ДатаГрафика
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ДатыГрафика.ДатаГрафика,
| ЕСТЬNULL(ДанныеГрафика.ДеньВключенВГрафик, ЛОЖЬ) КАК ДеньВключенВГрафик,
| ДниВключенныеВГрафик.КоличествоДнейВГрафикеСНачалаГода
|ИЗ
| ВТДатыГрафика КАК ДатыГрафика
| ЛЕВОЕ СОЕДИНЕНИЕ ВТКалендарныеГрафики КАК ДанныеГрафика
| ПО (ДанныеГрафика.Год = ГОД(ДатыГрафика.ДатаГрафика))
| И (ДанныеГрафика.ДатаГрафика = ДатыГрафика.ДатаГрафика)
| ЛЕВОЕ СОЕДИНЕНИЕ ВТКоличествоДнейВключенныхВГрафик КАК ДниВключенныеВГрафик
| ПО (ДниВключенныеВГрафик.ДатаГрафика = ДатыГрафика.ДатаГрафика)
|
|УПОРЯДОЧИТЬ ПО
| ДатыГрафика.ДатаГрафика";
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Если ВызыватьИсключение Тогда
СообщениеОбОшибке = НСтр("ru = 'График работы «%1» не заполнен на период %2.'");
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СообщениеОбОшибке, ГрафикРаботы, ПредставлениеПериода(ДатаНачала, КонецДня(ДатаОкончания)));
Иначе
Возврат Неопределено;
КонецЕсли;
КонецЕсли;
Выборка = Результат.Выбрать();
// Получаем выборку, в которой для каждой исходной даты определено количество дней,
// включенных в график с начала года.
// Из значения, заданного на первую дату выборки вычитаем все последующие,
// получая таким образом количество дней, включенных в график за весь период со знаком минус.
// Если первый день выборки является рабочим, а последующий - выходным,
// то количество дней включенных на обе эти даты будет одинаковым,
// в этом случае для корректировки добавляем к итоговому значению 1 день.
КоличествоДнейВГрафике = Неопределено;
ДобавлятьПервыйДень = Ложь;
Пока Выборка.Следующий() Цикл
Если КоличествоДнейВГрафике = Неопределено Тогда
КоличествоДнейВГрафике = Выборка.КоличествоДнейВГрафикеСНачалаГода;
ДобавлятьПервыйДень = Выборка.ДеньВключенВГрафик;
Иначе
КоличествоДнейВГрафике = КоличествоДнейВГрафике - Выборка.КоличествоДнейВГрафикеСНачалаГода;
КонецЕсли;
КонецЦикла;
Возврат - КоличествоДнейВГрафике + ?(ДобавлятьПервыйДень, 1, 0);
КонецФункции
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2019, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////