Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Adding and Subtracting Time to System.DateTime Ignoring Weekends

0.00/5 (No votes)
17 Dec 2012 1  
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 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here