Разбиение периода на отрезки времени с выделением отдельного отрезка.
Подобное разбиение периода на отрезки встречается, например, в документе Больничный лист,
где весь срок болезни сотрудника разбивается на месячные отрезки. Также, если больничный лист
является Первичным, то отделяется период три дня (идет первым) - он оплачивается по-другому.
//Вход: ДатаН, ДатаК, ОтдельныйОтрезокЧислоДней, метка
//
//Выход: Таблица значений. Меткой отмечен ОтдельныйОтрезок
//
//Пример: если ДатаН = 30.03.2016, ДатаК = 19.05.2016, ОтдельныйОтрезокЧислоДней = 10, метка = "*"
// то получится:
// | ДатаН | |ДатаК| |Метка| |КоличествоДней|
// 30.03.2016 31.03.2016 * 2
// 01.04.2016 08.04.2016 * 8
// 09.04.2016 30.04.2016 22
// 01.05.2016 19.05.2016 19
&НаСервере
функция ПолучитьОтрезки(ДатаН, ДатаК, ОтдельныйОтрезокЧислоДней, метка)
Если ТипЗнч(ДатаН) <> Тип("дата") ИЛИ ТипЗнч(ДатаК) <> Тип("дата") Тогда
возврат "Ошибка. Тип параметра ДатаНачала или датаОкончания не являются типом Дата";
КонецЕсли;
Если ТипЗнч(ОтдельныйОтрезокЧислоДней) <> Тип("Число") Тогда
возврат "Ошибка. Тип параметра ОтдельныйОтрезок должен быть Числом";
КонецЕсли;
Если ДатаН > ДатаК Тогда
возврат "Ошибка. Дата начала меньше или равна дате окончания";
КонецЕсли;
ОтдельныйОтрезокЧислоДней = Окр(ОтдельныйОтрезокЧислоДней);
Если ОтдельныйОтрезокЧислоДней < 0 Тогда
ОтдельныйОтрезокЧислоДней = -1*ОтдельныйОтрезокЧислоДней;
КонецЕсли;
//считаем количество месяцев, которые затрагивает период
МесяцНачалаПериода = НачалоМесяца(ДатаН);
МесяцОкончанияПериода = НачалоМесяца(ДатаК);
количествоМесяцев = 1;
Пока Истина Цикл
Если МесяцНачалаПериода = МесяцОкончанияПериода Тогда
прервать;
КонецЕсли;
МесяцНачалаПериода = ДобавитьМесяц(МесяцНачалаПериода, 1);
количествоМесяцев = количествоМесяцев + 1;
КонецЦикла;
//возвращаем значение
МесяцНачалаПериода = НачалоМесяца(ДатаН);
ТаблЗнач = Новый ТаблицаЗначений;
мас = новый массив;
мас.Добавить(тип("Дата"));
ОписаниеТипов = новый ОписаниеТипов(мас,,,,, новый КвалификаторыДаты(ЧастиДаты.Дата));
ТаблЗнач.Колонки.Добавить("ДатаН", ОписаниеТипов);
ТаблЗнач.Колонки.Добавить("ДатаК", ОписаниеТипов);
ТаблЗнач.Колонки.Добавить("Метка");
Если количествоМесяцев = 1 Тогда
НоваяСтрока = ТаблЗнач.Добавить();
НоваяСтрока.ДатаН = ДатаН;
НоваяСтрока.ДатаК = ДатаК;
Иначе
//первый отрезок
НоваяСтрока = ТаблЗнач.Добавить();
НоваяСтрока.ДатаН = ДатаН;
НоваяСтрока.ДатаК = НачалоДня(КонецМесяца(ДатаН));
//средние отрезки
ТекущийМесяц = МесяцНачалаПериода;
Для сс = 2 по КоличествоМесяцев-1 Цикл
ТекущийМесяц = ДобавитьМесяц(ТекущийМесяц, 1);
НоваяСтрока = ТаблЗнач.Добавить();
НоваяСтрока.ДатаН = ТекущийМесяц;
НоваяСтрока.ДатаК = НачалоДня(КонецМесяца(ТекущийМесяц));
КонецЦикла;
//последний отрезок
НоваяСтрока = ТаблЗнач.Добавить();
НоваяСтрока.ДатаН = НачалоМесяца(ДатаК);
НоваяСтрока.ДатаК = ДатаК;
КонецЕсли;
//отдельныйОтрезок
Если ОтдельныйОтрезокЧислоДней = 0 Тогда
ДополнитьКоличествомДней(ТаблЗнач);
возврат ТаблЗнач;
КонецЕсли;
ДнейВПериоде = (НачалоДня(ДатаК) - НачалоДня(ДатаН)) / 86400 + 1;
Если ДнейВПериоде < ОтдельныйОтрезокЧислоДней Тогда
Для каждого стр из ТаблЗнач Цикл
стр.Метка = Метка;
КонецЦикла;
иначе
ДатаОкончанияОтдельногоОтрезка = НачалоДня(ДатаН) + (ОтдельныйОтрезокЧислоДней-1)*86400;
Для каждого стр из ТаблЗнач Цикл
Если стр.ДатаН <= ДатаОкончанияОтдельногоОтрезка И ДатаОкончанияОтдельногоОтрезка <= стр.ДатаК Тогда
Если (стр.ДатаК - ДатаОкончанияОтдельногоОтрезка) = 0 Тогда
стр.Метка = Метка;
прервать;
Иначе
ДатаКВОтрезке = стр.ДатаК;
стр.ДатаК = ДатаОкончанияОтдельногоОтрезка;
стр.Метка = Метка;
индексТекущейСтроки = ТаблЗнач.Индекс(стр);
НоваяСтрока = ТаблЗнач.Вставить(индексТекущейСтроки + 1);
НоваяСтрока.ДатаН = ДатаОкончанияОтдельногоОтрезка + 86400;
НоваяСтрока.ДатаК = ДатаКВОтрезке;
прервать;
КонецЕсли;
иначе
стр.Метка = Метка;
КонецЕсли;
КонецЦикла;
КонецЕсли;
ДополнитьКоличествомДней(ТаблЗнач);
возврат ТаблЗнач;
КонецФункции
&НаСервере
Процедура ДополнитьКоличествомДней(ТЗ)
мас = новый массив;
мас.Добавить(тип("Число"));
ТЗ.Колонки.Добавить("КоличествоДней", новый ОписаниеТипов(мас));
Для каждого стр из ТЗ цикл
стр.КоличествоДней = (НачалоДня(стр.ДатаК) - НачалоДня(стр.ДатаН)) / 86400 + 1;
КонецЦикла;
КонецПроцедуры
//(можно убрать лишнее использование НачалоМесяца() )