Вычитание временных диапазонов Delphi из диапазона дат, вычисление оставшегося времени - PullRequest
2 голосов
/ 07 апреля 2010

Я ищу алгоритм, который поможет рассчитать продолжительность рабочего дня. Он будет иметь входной диапазон дат, а затем позволит вычитать частично или полностью пересекающиеся срезы временного диапазона из этого диапазона дат, и результатом будет количество минут (или дробная / кратная часть дня), оставшихся в исходном диапазоне дат, после вычитания различные срезы нерабочего времени.

Например:

Диапазон ввода даты: 04.01.2010 11:21 - 05.01.2010 15:00
Вычтите любые частично или полностью пересекающиеся кусочки, как это:
Удалить весь день воскресенье
Не по воскресеньям удалить с 11:00 до 12:00
Не по воскресеньям убрать время после 17:00
Не по воскресеньям снимите время до 8:00
Воскресенье - время 9:15 - 9:30
Вывод: количество оставшихся минут во входном диапазоне дат

Мне не нужно ничего слишком общего. Я мог бы жестко закодировать правила, чтобы упростить код. Если кто-нибудь знает пример кода или библиотеки / функции где-либо, или у него есть идеи псевдокода, я хотел бы начать с чего-нибудь. Я ничего не видел в DateUtils, например. Даже базовая функция, которая вычисляет количество минут наложения в двух диапазонах дат для вычитания, будет хорошим началом.

Ответы [ 2 ]

4 голосов
/ 07 апреля 2010

Интересные требования ... Но не так сложно добиться "жестко закодированным" способом.

Наслаждайтесь

uses
  Math, DateUtils;

function TimeRangeOverlap(Range1Start, Range1Finish, Range2Start, Range2Finish : TDateTime) : TDateTime;
begin
  Result := Max(Min(Range1Finish, Range2Finish) - Max(Range1Start, Range2Start), 0);
end;

function TotalTime(Start, Finish : TDateTime) : TDateTime;
var DayStart, DayFinish : TDateTime;
    I : Integer;
begin
  Result := 0;
  for I := Floor(Start) to Floor(Finish) do  //For each day in range;
  begin
    if DayOfWeek(I) = 1 then CONTINUE; //Remove all sundays.

    DayStart := Max(Start, I);     //Midnight on the start of the day, except on the first day;
    DayFinish   := Min(Finish, I + 1 - OneMillisecond); //Midnight minus 1 msec of the following day.

    Result := Result + DayFinish - DayStart;

    //Adjustment part
    Result := Result - TimeRangeOverlap(DayStart, DayFinish, I + EncodeTime(11,00,00,00), I + EncodeTime(12,00,00,00)); //Remove time between 11:00 and 12:00
    Result := Result - TimeRangeOverlap(DayStart, DayFinish, I + EncodeTime(17,00,00,00), I + 1); //Remove time after 5:00 PM
    Result := Result - TimeRangeOverlap(DayStart, DayFinish, I                          , I + EncodeTime(8,00,00,00)); //Remove time after 8:00 AM
    Result := Result - TimeRangeOverlap(DayStart, DayFinish, I + EncodeTime(9,15,00,00), I + EncodeTime(9,30,00,00)); //Remove time between 9:15 and 9:30
  end;
end;
1 голос
/ 07 апреля 2010

Просто используйте подпрограммы в DateUtils и в других местах для реализации правил, которые вы сами описываете.

Если вам нужна идея, чтобы начать работу, я бы предложил подсчитать минуты во входном диапазоне (помня, что значение TDateTime является плавающей точкой, где целое значение - это число дней и дробная часть). является частью дня), затем увеличивается через диапазон и для каждого целочисленного шага (дня) вычитает соответствующее количество минут для этого дня из общего количества на основе ваших правил и времени начала / окончания первого / последнего дня в диапазон, в котором эти дни встречаются в диапазоне (промежуточные дни, конечно, завершаются 24-часовыми периодами).

Действительно, чтобы предоставить более подробный «план», можно было бы также выполнить для вас полную рутину, что я мог бы сделать, если бы у меня было больше времени, чего, к сожалению, сейчас нет.

...