Wednesday, April 23, 2014

C# DateTime Add Business Days - Without Looping

I recently had to add the number of business days to a C# DateTime object, which DateTime does not currently support. I did a quick search on Google, and came up with some looping solutions, so decided to write my own O(1) solution.

I implemented the AddBusinessDays() method as an C# extension method on the DateTime object. Now, the AddBusinessDays() method can be used anywhere in the code!

        public static DateTime AddBusinessDays(this DateTime date, int numBusinessDays)
        {
            DateTime adjustedDate = date;

            /* First, we want to normalize the days to the upcoming Monday
             * Get the number of days to Monday
             */
            int daysUntilMonday = DaysUntilMonday(date);
            int daysToAdd = numBusinessDays;

            // Too many days until Monday
            if (daysUntilMonday > daysToAdd)
            {
                adjustedDate = adjustedDate.AddDays(daysToAdd);

                // Check to see if we're on the weekend
                int endDateDaysUntilMonday = DaysUntilMonday(adjustedDate);

                // Landed on a weekend
                if (endDateDaysUntilMonday <= 2)
                {
                    // Days from Friday - we need to add these back on to the end
                    daysToAdd = 3 - endDateDaysUntilMonday;

                    // Normalize to Sunday, then add the days we have not yet added
                    adjustedDate = adjustedDate.AddDays(endDateDaysUntilMonday - 1 + daysToAdd);
                }
            }
            else
            {
                // Normalize to Monday
                adjustedDate = adjustedDate.AddDays(daysUntilMonday);

                daysToAdd -= Math.Max(daysUntilMonday - 2, 0);

                // Calculate the number of weekends added
                int weekendsAdded = (int)(daysToAdd / 5.0);
                daysToAdd += weekendsAdded * 2;

                // Add a day for each weekend day
                adjustedDate = adjustedDate.AddDays(daysToAdd);
            }

            return adjustedDate;
        }

        private static int DaysUntilMonday(DateTime date)
        {
            int daysUntilMonday = DayOfWeek.Monday - date.DayOfWeek;

            if (daysUntilMonday < 0)
            {
                daysUntilMonday += 7;
            }

            return daysUntilMonday;
        }