Adding and Subtracting Time to System.DateTime Ignoring Weekends
Adding and subtracting with dates and times ignoring weekends
Introduction
In this tip, I provide a code solution for a problem which I couldn't find a good solution for on the web myself. The problem is that in some situations you want to calculate with dates and times without using the weekends. For example, when the company is closed on weekends and you want to calculate how many working days a product is in production.
Background
There are a few examples around which provide us with a method to get the number of working days between two System.DateTime
objects and add a specified number of working days to a System.DateTime
object. Unfortunately these solutions are only precise to days. In many situations, you also want to reckon with hours, minutes and seconds.
Using the Code
I've written two extension methods which apply to System.DateTime
objects. Adding the class found below to your project will automatically make these methods available on your System.DateTime
objects. However this is not always necessary. These methods can also easily be modified to work as normal methods.
using System;
namespace Middelpat.Extensions
{
/// <summary>
/// Class containing a number of extension methods applied
/// to the calendar category (e.g. System.DateTime, System.TimeSpan)
/// </summary>
public static class CalenderExtensions
{
/// <summary>
/// Calculates the time between two dates excluding weekends
/// </summary>
/// <param name="startDate">System.DateTime startdate</param>
/// <param name="end">System.DateTime enddate</param>
/// <returns>System.TimeSpan time between</returns>
public static TimeSpan SubstractDateExcludingWeekends
(this DateTime startDate, DateTime end)
{
TimeSpan betweenTime = end - startDate;
int numberOfWeekendDays = 0;
if (startDate.DayOfWeek == DayOfWeek.Saturday)
{
//Subtract the time left in the Saturday and the whole Sunday
betweenTime -= new TimeSpan(1, (23 - startDate.Hour),
(59 - startDate.Minute), (60 - startDate.Second));
}
else if (startDate.DayOfWeek == DayOfWeek.Sunday)
{
//Subtract the time left in the Sunday
betweenTime -= new TimeSpan((23 - startDate.Hour),
(59 - startDate.Minute), (60 - startDate.Second));
}
//We handle Sunday later in the function
else if (end.DayOfWeek <
startDate.DayOfWeek && end.DayOfWeek != DayOfWeek.Sunday)
{
numberOfWeekendDays += 2;
}
//fix for 6 days
int betweenDays = betweenTime.Days;
betweenDays = betweenDays % 7 == 6 ? betweenDays += 1 : betweenDays;
numberOfWeekendDays += ((int)((decimal)betweenDays / 7m) * 2);
if (end.DayOfWeek == DayOfWeek.Saturday)
{
//We've counted the time in this Saturday
//while this isn't allowed, so subtract it
betweenTime -= new TimeSpan(end.Hour, end.Minute, end.Second);
}
else if (end.DayOfWeek == DayOfWeek.Sunday)
{
//We've counted the time in this Sunday and
//the Saturday while this isn't allowed, so subtract it
betweenTime -= new TimeSpan(1, end.Hour, end.Minute, end.Second);
}
return betweenTime - new TimeSpan(numberOfWeekendDays, 0, 0, 0);
}
/// <summary>
/// Returns the new System.DateTime not calculating the weekends
/// when adding a System.TimeSpan
/// </summary>
/// <param name="startDate">System.DateTime startdate</param>
/// <param name="time">System.TimeSpan
/// time to add to the startdate</param>
/// <returns>The new System.DateTime</returns>
public static DateTime AddTimeSpanExcludingWeekends
(this DateTime startDate, TimeSpan time)
{
DateTime newDate = startDate;
if (startDate.DayOfWeek == DayOfWeek.Saturday)
{
//Add the time left in the Saturday and the whole Sunday
newDate += new TimeSpan(1, (23 - startDate.Hour),
(59 - startDate.Minute), (60 - startDate.Second));
}
else if (startDate.DayOfWeek == DayOfWeek.Sunday)
{
//Add the time left in the Sunday
newDate += new TimeSpan((23 - startDate.Hour),
(59 - startDate.Minute), (60 - startDate.Second));
}
int weekDayCount = time.Days;
TimeSpan timeLefAfterLoop = time - new TimeSpan(time.Days, 0 , 0, 0);
for (int i = 0; i < weekDayCount; i++)
{
newDate = newDate.AddDays(1);
if (newDate.DayOfWeek == DayOfWeek.Saturday)
{
newDate = newDate.AddDays(2);
}
}
//Now only add the remaining hours minutes and seconds
newDate += timeLefAfterLoop;
//Check if we ended om on a weekend day
if (newDate.DayOfWeek == DayOfWeek.Saturday)
{
//Add two more days to get rid of Saturday
newDate = newDate.AddDays(2);
}
else if (newDate.DayOfWeek == DayOfWeek.Sunday)
{
//Add one day to get rid of Sunday.
//However I don't think we'll ever end up here
//because we add one day per cycle of the loop
//and skip the Saturday by adding two days. But just to be sure :)
newDate = newDate.AddDays(1);
}
return newDate;
}
}
}
History
- 23-10-2012: Initial version