Subtracting Delphi Time Ranges from a Date Range, Calculate Remaining Time
I'm looking for an algorithm that will help calculate a workday working time length. It would have an input date range and then allow subtracting partially or completely intersecting time range slices from that date range and the result would be the number of minutes (or the fraction/multiple of a day) left in the original da开发者_高级运维te range, after subtracting out the various non-working time slices.
For Example:
Input date range: 1/4/2010 11:21 am - 1/5/2010 3:00 pm
Subtract out any partially or completely intersecting slices like this: Remove all day Sunday Non-Sundays remove 11:00 - 12:00 Non-Sundays remove time after 5:00 pm Non-Sundays remove time before 8:00 am Non-Sundays remove time 9:15 - 9:30 am Output: # of minutes left in the input date rangeI don't need anything overly-general. I could hardcode the rules to simplify the code. If anyone knows of sample code or a library/function somewhere, or has some pseudo-code ideas, I'd love something to start with. I didn't see anything in DateUtils, for example. Even a basic function that calculates the number of minutes of overlap in two date ranges to subtract out would be a good start.
Interesting requirements... But not so hard to achieve in a "hardcoded" way.
Enjoy
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;
Simply use the routines in DateUtils and elsewhere to implement the rules you yourself describe.
If you want an idea to get you started, off the cuff I'd suggest calculating the minutes in your input range (remembering that a TDateTime value is a floating point where the integral value is the number of days and the fractional part is a portion of a day) then incrementing thru the range and for each integer step (day) subtract the appropriate number of minutes for that day from the total based on your rules and the start/end-time of the first/last days in the range when those days are encountered in the range (intervening days being of course complete 24 hour periods).
Really to provide any more detailed "outline" one might as well implement the complete routine for you, which I might do if I had more time, which sadly I don't right now.
精彩评论