How can one calculate the Nth non holiday from a given date?

Let's say I have a List<DateTime> L that contains holidays dates in the US. Let DateTime d be today 2017/10/19. I want to calculate the next n-th non-holiday date (where n is a positive integer let's say) consecutive to d.

To do this, a concept of "iteration over all dates >= d except dates belonging to L" is involved. What is the best c# design to handle this ? (Performance is quite important.)

Remarks :

  1. at each non-holiday date in the "iteration" process, I will use the current non-holiday date to perform a calculation with it
  2. n could be like 40-50 times "365"
  3. the set of holidays dates is finite indeed, I don't use holiday calendars defined with generation rules
  4. I am also interested in created the list of "iterated" non-holidays days until the "d+n", or the list of non-holidays dates between two dates
Jon Skeet
people
quotationmark

If the set of holidays is finite (and reasonably small)

It's really easy to create an infinite sequence of dates:

static IEnumerable<DateTime> GetDates(DateTime start)
{
    DateTime current = start;
    while (true)
    {
        yield return current;
        current = current.AddDays(1);
    }
}

Then you can use Except with your holidays to get an infinite stream of dates except your holidays:

var nonHolidays = GetDates(DateTime.Today).Except(holidays);

To get the nth value (starting with 0 as the first) you can use ElementAt:

var specificWorkDay = nonHolidays.ElementAt(n);

Of course if you're doing this a lot, you might want to generate "all the first X non-holiday dates" which is easy too:

var multipleWorkDays = nonHolidays.Take(x).ToList();

Note that even though GetDates looks like it's in an infinite loop, that just means it will keep iterating forever if you keep asking the returned iterator for data (and until you hit DateTime.MaxValue of course). It will only iterate as far as you ask it to. Just don't call GetDates().ToList() or nonHolidays.ToList()!

With a potentially-infinite sequence of holidays

Suppose you have an IEnumerable<DateTime> GetHolidays(DateTime start) method which returns a sequence of holidays in order, potentially infinite, from the given start date. (It's very important that the sequence is in order, as otherwise we can't tell reliably whether or not a date is a holiday.)

At that point, you need to be slightly smarter, as Except is not going to work. It's still possible to do efficiently though:

static IEnumerable<DateTime> GetNonHolidays(DateTime start)
{
    var holidays = GetHolidays(start);
    var current = start;
    foreach (var holiday in holidays)
    {
        // Yield everything until the next holiday
        while (current < holiday)
        {
            yield return current;
            current = current.AddDays(1);
        }
        // Skip this holiday, then look for the next one
        current = current.AddDays(1);
    }
    // No more holidays? Now we can just yield infinitely...
    while (true)
    {
        yield return current;
        current = current.AddDays(1);
    }
}

people

See more on this question at Stackoverflow