I need to determine duration between two DateTimes in minutes.
However, there is a slight twist:
My implementation :) The idea is to quickly compute the total weeks, and walk the remaining week day by day...
public TimeSpan Compute(DateTime start, DateTime end)
{
// constant start / end times per day
TimeSpan sevenAM = TimeSpan.FromHours(7);
TimeSpan sevenPM = TimeSpan.FromHours(19);
if( start >= end )
{
throw new Exception("invalid date range");
}
// total # of weeks
int completeWeeks = ((int)(end - start).TotalDays) / 7;
// starting total
TimeSpan total = TimeSpan.FromHours(completeWeeks * 12 * 5);
// adjust the start date to be exactly "completeWeeks" past its original start
start = start.AddDays(completeWeeks * 7);
// walk days from the adjusted start to end (at most 7), accumulating time as we can...
for(
// start at midnight
DateTime dt = start.Date;
// continue while there is time left
dt < end;
// increment 1 day at a time
dt = dt.AddDays(1)
)
{
// ignore weekend
if( (dt.DayOfWeek == DayOfWeek.Saturday) ||
(dt.DayOfWeek == DayOfWeek.Sunday) )
{
continue;
}
// get the start/end time for each day...
// typically 7am / 7pm unless we are at the start / end date
TimeSpan dtStartTime = ((dt == start.Date) && (start.TimeOfDay > sevenAM)) ?
start.TimeOfDay : sevenAM;
TimeSpan dtEndTime = ((dt == end.Date) && (end.TimeOfDay < sevenPM)) ?
end.TimeOfDay : sevenPM;
if( dtStartTime < dtEndTime )
{
total = total.Add(dtEndTime - dtStartTime);
}
}
return total;
}
Use TimeSpan.TotalMinutes, subtract non-business days, subtract superfluous hours.
Try the following DiffRange function.
public static DateTime DayStart(DateTime date)
{
return date.Date.AddHours(7);
}
public static DateTime DayEnd(DateTime date)
{
return date.Date.AddHours(19);
}
public static TimeSpan DiffSingleDay(DateTime start, DateTime end)
{
if ( start.Date != end.Date ) {
throw new ArgumentException();
}
if (start.DayOfWeek == DayOfWeek.Saturday || start.DayOfWeek == DayOfWeek.Sunday )
{
return TimeSpan.Zero;
}
start = start >= DayStart(start) ? start : DayStart(start);
end = end <= DayEnd(end) ? end : DayEnd(end);
return end - start;
}
public static TimeSpan DiffRange(DateTime start, DateTime end)
{
if (start.Date == end.Date)
{
return DiffSingleDay(start, end);
}
var firstDay = DiffSingleDay(start, DayEnd(start));
var lastDay = DiffSingleDay(DayStart(end), end);
var middle = TimeSpan.Zero;
var current = start.AddDays(1);
while (current.Date != end.Date)
{
middle = middle + DiffSingleDay(current.Date, DayEnd(current.Date));
current = current.AddDays(1);
}
return firstDay + lastDay + middle;
}