Click here to Skip to main content
Click here to Skip to main content

Adding and Subtracting Time to System.DateTime Ignoring Weekends

By , 17 Dec 2012
 

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

middelpat
Software Developer (Junior)
Netherlands Netherlands
Student software engineer and partime .NET backend developer

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130617.1 | Last Updated 17 Dec 2012
Article Copyright 2012 by middelpat
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid