РазностьДатПоКалендарю (БСП)

Автор: 1С
ОбщийМодуль.КалендарныеГрафики
БСП

Разность дат по календарю. Определяет количество дней, входящих в график, для указанного периода.

// Определяет количество дней, входящих в график, для указанного периода.
//
// Параметры:
//	 ГрафикРаботы	- СправочникСсылка.Календари, СправочникСсылка.ПроизводственныеКалендари - график или 
//                    производственный календарь, который необходимо использовать для расчета дней.
//	 ДатаНачала		- Дата - дата начала периода.
//	 ДатаОкончания	- Дата - дата окончания периода.
//	 ВызыватьИсключение - Булево - если Истина, вызвать исключение в случае незаполненного графика.
//
// Возвращаемое значение:
//	 Число		- количество дней между датами начала и окончания.
//	              Если график ГрафикРаботы не заполнен, и ВызыватьИсключение = Ложь, возвращается Неопределено.
//
Функция РазностьДатПоКалендарю(Знач ГрафикРаботы, Знач ДатаНачала, Знач ДатаОкончания, ВызыватьИсключение = Истина) Экспорт
	
	Если Не ЗначениеЗаполнено(ГрафикРаботы) Тогда
		Если ВызыватьИсключение Тогда
			ВызватьИсключение НСтр("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
///////////////////////////////////////////////////////////////////////////////////////////////////////

Рекомендации

Похожие публикации

Раскрасить даты календаря

Добавить к дате и разность дат

ДатыПоКалендарю (БСП)

ДатаПоКалендарю (БСП)

Прибавить рабочие дни к дате

Прибавить рабочие дни к дате (Запрос)

РазностьМассивов (БСП)

ВерсияКалендарей (БСП)

ПриОбновленииПроизводственныхКалендарей (БСП)

Обновлятор-1С: групповое (пакетное) обновление и обслуживание всех баз за один раз