+7(960) 250-82-68 spam@mirossa.ru


  MCU         C           1С         PHP       JAVA      разное 


Статьи
 
 

Разбиение периода на отрезки времени с выделением отдельного отрезка.


Подобное разбиение периода на отрезки встречается, например, в документе Больничный лист,
где весь срок болезни сотрудника разбивается на месячные отрезки. Также, если больничный лист
является Первичным, то отделяется период три дня (идет первым) - он оплачивается по-другому.


//Вход: ДатаН, ДатаК, ОтдельныйОтрезокЧислоДней, метка
//
//Выход: Таблица значений. Меткой отмечен ОтдельныйОтрезок
//
//Пример: если ДатаН = 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;
  КонецЦикла;

КонецПроцедуры

  //(можно убрать лишнее использование НачалоМесяца() )