I need to determine duration between two DateTimes in minutes.
However, there is a slight twist:
I won't write any code, but having a DateTime you can tell the Day of the week, thus you know how many weekends are in your range, so you can tell how many minutes are in a weekend.
So it wouldn't be so hard... of course there must be an optimal one line solution... but i think you can get around with this one.
I forgot to mention that you also know the minutes btween 7:00 pm and 7:00 am so all you have to do is substract the right amount of minutes to the time difference you get.
static int WorkPeriodMinuteDifference(DateTime start, DateTime end)
{
//easier to only have to work in one direction.
if(start > end)
return WorkPeriodMinuteDifference(end, start);
//if weekend, move to start of next Monday.
while((int)start.DayOfWeek % 6 == 0)
start = start.Add(new TimeSpan(1, 0, 0, 0)).Date;
while((int)end.DayOfWeek % 6 == 0)
end = end.Add(new TimeSpan(1, 0, 0, 0)).Date;
//Move up to 07:00 or down to 19:00
if(start.TimeOfDay.Hours < 7)
start = new DateTime(start.Year, start.Month, start.Day, 7, 0, 0);
else if(start.TimeOfDay.Hours > 19)
start = new DateTime(start.Year, start.Month, start.Day, 19, 0, 0);
if(end.TimeOfDay.Hours < 7)
end = new DateTime(end.Year, end.Month, end.Day, 7, 0, 0);
else if(end.TimeOfDay.Hours > 19)
end = new DateTime(end.Year, end.Month, end.Day, 19, 0, 0);
TimeSpan difference = end - start;
int weeks = difference.Days / 7;
int weekDays = difference.Days % 7;
if(end.DayOfWeek < start.DayOfWeek)
weekDays -= 2;
return (weeks * 5 * 12 * 60) + (weekDays * 12 * 60) + difference.Hours * 60 + difference.Minutes
}
Take your start time, get the amount of minutes to the end of that day (Ie the 7pm).
Then from the 7am the next day, count the amount of days to the final day (excluding any time into the end day).
Calculate how many (If any) weekends have passed. (For every weekends reduce the count of days by 2).
Do some simple math from there to get the total minutes for the count of days.
Add the extra time on the final day and the start days extra time.
I'm sure there's something I missed.
TimeSpan CalcBusinessTime(DateTime a, DateTime b)
{
if (a > b)
{
DateTime tmp = a;
a = b;
b = tmp;
}
if (a.TimeOfDay < new TimeSpan(7, 0, 0))
a = new DateTime(a.Year, a.Month, a.Day, 7, 0, 0);
if (b.TimeOfDay > new TimeSpan(19, 0, 0))
b = new DateTime(b.Year, b.Month, b.Day, 19, 0, 0);
TimeSpan sum = new TimeSpan();
TimeSpan fullDay = new TimeSpan(12, 0, 0);
while (a < b)
{
if (a.DayOfWeek != DayOfWeek.Saturday && a.DayOfWeek != DayOfWeek.Sunday)
{
sum += (b - a < fullDay) ? b - a : fullDay;
}
a = a.AddDays(1);
}
return sum;
}
You can, of course, use LINQ:
DateTime a = new DateTime(2010, 10, 30, 21, 58, 29);
DateTime b = a + new TimeSpan(12, 5, 54, 24, 623);
var minutes = from day in a.DaysInRangeUntil(b)
where !day.IsWeekendDay()
let start = Max(day.AddHours( 7), a)
let end = Min(day.AddHours(19), b)
select (end - start).TotalMinutes;
var result = minutes.Sum();
// result == 6292.89
(Note: You probably need to check for a lot of corner cases which I completely ignored.)
Helper methods:
static IEnumerable<DateTime> DaysInRangeUntil(this DateTime start, DateTime end)
{
return Enumerable.Range(0, 1 + (int)(end.Date - start.Date).TotalDays)
.Select(dt => start.Date.AddDays(dt));
}
static bool IsWeekendDay(this DateTime dt)
{
return dt.DayOfWeek == DayOfWeek.Saturday
|| dt.DayOfWeek == DayOfWeek.Sunday;
}
static DateTime Max(DateTime a, DateTime b)
{
return new DateTime(Math.Max(a.Ticks, b.Ticks));
}
static DateTime Min(DateTime a, DateTime b)
{
return new DateTime(Math.Min(a.Ticks, b.Ticks));
}
It was a pretty hard question. For a basic, in a straightforward approach, I have written the below code:
DateTime start = new DateTime(2010, 01, 01, 21, 00, 00);
DateTime end = new DateTime(2010, 10, 01, 14, 00, 00);
// Shift start date's hour to 7 and same for end date
// These will be added after doing calculation:
double startAdjustmentMinutes = (start - start.Date.AddHours(7)).TotalMinutes;
double endAdjustmentMinutes = (end - end.Date.AddHours(7)).TotalMinutes;
// We can do some basic
// mathematical calculation to find weekdays count:
// divide by 7 multiply by 5 gives complete weeks weekdays
// and adding remainder gives the all weekdays:
int weekdaysCount = (((int)((end.Date - start.Date).Days / 7) * 5)
+ ((end.Date - start.Date).Days % 7));
// so we can multiply it by minutes between 7am to 7 pm
int minutes = weekdaysCount * (12 * 60);
// after adding adjustment we have the result:
int result = minutes + startAdjustmentMinutes + endAdjustmentMinutes;
I know this not seem programmatically beautiful but I don't know if it is good to iterate through days and hours between start and end.