&НаСервере
Процедура ОбъединитьНаСервере(ТЗ)
ТП = ТЗ.Скопировать();
Для Каждого ОС из ТЗ Цикл
ТП = ОбъединитьПериоды(ТП,ОС);
КонецЦикла;
ТП.Свернуть("ДатаНачала,ДатаОкончания");
ТП.Сортировать("ДатаНачала, ДатаОкончания");
ТЗ = ТП;
КонецПроцедуры
//Объединяет пересекающиеся периоды в один.
//ТП - Таблица значений - предварительная таблица с периодами.
//ОС - Строка таблицы значений - объединяемая строка.
&НаСервере
Функция ОбъединитьПериоды(ТП, ОС)
Н = ТП.Количество()-1;
Пока Н>=0 Цикл
СП = ТП[Н];
Если (СП.ДатаНачала>ОС.ДатаОкончания+86400 ИЛИ СП.ДатаОкончания<ОС.ДатаНачала-86400) Тогда
//не пересекаются
ИначеЕсли СП.ДатаНачала>=ОС.ДатаНачала И СП.ДатаОкончания<=ОС.ДатаОкончания Тогда
//берем накрывающий период
ЗаполнитьЗначенияСвойств(СП,ОС);
ИначеЕсли СП.ДатаНачала<ОС.ДатаНачала И СП.ДатаОкончания>ОС.ДатаОкончания Тогда
//оставляем накрывающий период
ИначеЕсли СП.ДатаНачала<=ОС.ДатаОкончания+86400 И СП.ДатаОкончания>ОС.ДатаОкончания Тогда
//объединить с левым
СП.ДатаНачала = ОС.ДатаНачала;
ИначеЕсли СП.ДатаНачала<ОС.ДатаНачала И СП.ДатаОкончания>=ОС.ДатаНачала-86400 Тогда
//объединить с правым
СП.ДатаОкончания = ОС.ДатаОкончания;
КонецЕсли;
Н=Н-1;
КонецЦикла;
Возврат ТП
КонецФункции
&НаСервере
Процедура РассчитатьНаСервере()
ТП = РеквизитФормыВЗначение("Периоды");
ОбъединитьНаСервере(ТП);
ЗначениеВРеквизитФормы(ТП,"Периоды");
УдТП = РеквизитФормыВЗначение("УдаляемыеПериоды");
ОбъединитьНаСервере(УдТП);
ЗначениеВРеквизитФормы(УдТП,"УдаляемыеПериоды");
ТПФин = ТП.Скопировать();
//Удалим удаляемые периоды из периодов.
Для каждого УС из УдТП Цикл
ТПФин = УдалитьПериод(ТПФин, УС);
КонецЦикла;
ТПФин.Сортировать("ДатаНачала, ДатаОкончания");
ЗначениеВРеквизитФормы(ТПФин,"Результат");
//Посчитаем дни в табличных частях.
СуммаДнейТП = 0;
СуммаДнейУдТП = 0;
СуммаДнейТПФин = 0;
Для каждого Строка из ТП Цикл
СуммаДнейТП = СуммаДнейТП + (КонецДня(Строка.ДатаОкончания) + 1 - НачалоДня(Строка.ДатаНачала))/86400;
КонецЦикла;
Для каждого Строка из УдТП Цикл
СуммаДнейУдТП = СуммаДнейУдТП + (КонецДня(Строка.ДатаОкончания) + 1 - НачалоДня(Строка.ДатаНачала))/86400;
КонецЦикла;
Для каждого Строка из ТПФин Цикл
СуммаДнейТПФин = СуммаДнейТПФин + (КонецДня(Строка.ДатаОкончания) + 1 - НачалоДня(Строка.ДатаНачала))/86400;
КонецЦикла;
КонецПроцедуры
//Возвращает ТЗ из периодов которой удаляются периоды
//ТП - Таблица значений - предварительная таблица с периодами.
//УС - Строка таблицы значений - удаляемая строка.
Функция УдалитьПериод(ТП, УС)
Н = ТП.Количество()-1;
Пока Н>=0 Цикл
СП = ТП[Н];
Если (СП.ДатаНачала>УС.ДатаОкончания ИЛИ СП.ДатаОкончания<УС.ДатаНачала) Тогда
//не попадает
ИначеЕсли СП.ДатаНачала>=УС.ДатаНачала И СП.ДатаОкончания<=УС.ДатаОкончания Тогда
//удаляем строку
ТП.Удалить(СП);
ИначеЕсли СП.ДатаНачала<УС.ДатаНачала И СП.ДатаОкончания>УС.ДатаОкончания Тогда
//добавить 2 и удалить 1
ССлева = ТП.Вставить(Н);
ЗаполнитьЗначенияСвойств(ССлева,СП);
ССлева.ДатаОкончания = УС.ДатаНачала-86400;
ССправа = ТП.Вставить(Н);
ЗаполнитьЗначенияСвойств(ССправа,СП);
ССправа.ДатаНачала = УС.ДатаОкончания+86400;
ТП.Удалить(СП);
ИначеЕсли СП.ДатаНачала<=УС.ДатаОкончания И СП.ДатаОкончания>УС.ДатаОкончания Тогда
//обрезать слева
СП.ДатаНачала = УС.ДатаОкончания+86400;
ИначеЕсли СП.ДатаНачала<УС.ДатаНачала И СП.ДатаОкончания>=УС.ДатаНачала Тогда
//обрезать справа
СП.ДатаОкончания = УС.ДатаНачала-86400;
КонецЕсли;
Н=Н-1;
КонецЦикла;
Возврат ТП
КонецФункции