Number of days in date range, excluding weekends and other dates, in C#

19,661

Solution 1

Here's one example that includes the excluded dates, weekends, and looping. I did change the string excludeDates to a List though. Some null checking should be added.

    public static int DaysLeft(DateTime startDate, DateTime endDate, Boolean excludeWeekends, List<DateTime> excludeDates)
    {
        int count = 0;
        for (DateTime index = startDate; index < endDate; index = index.AddDays(1))
        {
            if (excludeWeekends && index.DayOfWeek != DayOfWeek.Sunday && index.DayOfWeek != DayOfWeek.Saturday)
            {
                bool excluded = false; ;
                for (int i = 0; i < excludeDates.Count; i++)
                {
                    if (index.Date.CompareTo(excludeDates[i].Date) == 0)
                    {
                        excluded = true;
                        break;
                    }
                }

                if (!excluded)
                {
                    count++;
                }
            }
        }

        return count;
    }

EDIT: I do want to point out that I would consider this the quick and dirty method - if you didn't have to do this often. If you're performing this a lot and the distance between the startDate and endDate is rather large it would be much better to do the math as stated in one of the other answers. This is suggested in order to get a feel for iterating dates.

Solution 2

Oh it's really easy to loop through the dates - that's not a problem at all:

// I'm assuming you want <= to give an *inclusive* end date...
for (DateTime date = start; date <= end; date = date.AddDays(1))
{
     // Do stuff with date
}

You could easily write an IEnumerable<DateTime> too, and use foreach.

I'd try to avoid doing string operations here if possible though - fundamentally these dates aren't strings, so if you can work in the problem domain as far as possible, it'll make things easier.

Of course there may well be more efficient ways than looping, but they'll be harder to get right. If the loop is okay in terms of performance, I'd stick to that.

As a quick plug for my own open source project, Noda Time has a rather more diverse set of types representing dates and times - in this case you'd use LocalDate. That way you don't have to worry about what happens if the time in "start" is later than the time in "end" etc. On the other hand, Noda Time isn't really finished yet... the bits you need for this are ready and should work fine, but it's possible the API could still change in the future.

EDIT: If you do need to loop through dates frequently, you might want something like this extension method (put it in a top-level non-generic static class):

public static IEnumerable<DateTime> To(this DateTime start, DateTime end)
{
    Date endDate = end.Date;
    for (DateTime date = start.Date; date <= endDate; date = date.AddDays(1))
    {
        yield return date;            
    }
}

Then:

foreach (DateTime date in start.To(end))
{
    ...
}

Solution 3

The Subsonic sugar library has a lot of helpers to handle DateTime manipulation.

You can find a full list on the Subsonic site and the source code is in github.

Share:
19,661
Dan
Author by

Dan

Updated on June 18, 2022

Comments

  • Dan
    Dan almost 2 years

    I have a C# method like this:

    public static int DaysLeft(DateTime startDate, DateTime endDate, Boolean excludeWeekends, String excludeDates)
    {
    }
    

    What it's supposed to do is calculate the number of days between the startDate and endDate, but optionally needs to exclude weekends and also other dates (passed in as a comma-separated string of dates).

    I have absolutely no idea how to tackle this. My gut instinct would be to loop from startDate to endDate and do some string comparisons, but from what I can find out, C# doesn't allow looping through dates in that way - or at least it's not a very elegant way of doing things.

  • macleojw
    macleojw almost 13 years
    To avoid the string comparison for excluding dates, all you need to do is find the number of dates you're excluding (assuming there are no weekends) which you can find out with: excludeDates.split(',').length. Then subtract this from the number of days.
  • Dan
    Dan almost 13 years
    The exclude dates might not necessarily fall within the start and end dates though, so there needs to be a check here - which is part of the difficulty and means I can't do it the way you suggest.
  • user2316116
    user2316116 over 7 years
    Instead of doing a loop for (int i = 0; i < excludeDates.Count; i++) {...} you can simply check excludeDates.Contents(index) and then the entire code could be simplified to just 2 lines if (excludeWeekends && index.DayOfWeek != DayOfWeek.Sunday && index.DayOfWeek != DayOfWeek.Saturday && !excludeDates.Contains(index)) count++;