Click here to Skip to main content
15,884,298 members
Articles / Programming Languages / C#
Tip/Trick

Adding and Subtracting Time to System.DateTime Ignoring Weekends

Rate me:
Please Sign up or sign in to vote.
4.67/5 (3 votes)
17 Dec 2012CPOL 20.5K   11   2
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.  

C#
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)


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

Comments and Discussions

 
BugWrong result Pin
Member 958023221-Feb-15 9:57
Member 958023221-Feb-15 9:57 
QuestionThank you Pin
saad7494-Nov-14 22:58
saad7494-Nov-14 22:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.