Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C#, what is the best way to find gaps in a DateTime array?

I have a list of dates that are apart by a month in the sense that all dates are the "First Monday of the month". In some cases months are missing so I need to write a function to determine if all dates are consecutive

So for example if this was the list of dates, the function would return true as all items are the "First Friday of the month" and there are no gaps. This example below would return true.

 var date = new DateTime(2013, 1, 4);
 var date1 = new DateTime(2013, 2, 1);
 var date2 = new DateTime(2013, 3, 1);
 var date3 = new DateTime(2013, 4, 5);

 var dateArray = new DateTime[]{date, date1, date2, date3};
 bool isConsecutive = IsThisListConsecutive(dateArray);

where this example below would return false because, even though they are also all "First Friday of the month", its missing the March 2013 item.

 var date = new DateTime(2013, 1, 4);
 var date1 = new DateTime(2013, 2, 1);
 var date3 = new DateTime(2013, 4, 5);

 var dateArray = new DateTime[]{date, date1, date3};
 bool isConsecutive = IsThisListConsecutive(dateArray);

so i am trying to figure out the right logic for the IsThisListConsecutive() method:

Here was my first try: (Note I already know upfront that all dates are same day of week and same week of month so the only thing i am looking for is a missing slot)

  private bool IsThisListConsecutive(IEnumerable<DateTime> orderedSlots)
    {
        DateTime firstDate = orderedSlots.First();
        int count = 0;
        foreach (var slot in orderedSlots)
        {
            if (slot.Month != firstDate.AddMonths(count).Month)
            {
                return false;
            }
            count++;
        }
        return true;
    }

This code above works exept if the list crosses over from one year to another. I wanted to get any advice on a better way to create this function and how that line could be rewritten to deal with dates that cross over years.

like image 938
leora Avatar asked Mar 11 '13 01:03

leora


2 Answers

So to implement this we'll start with a simple helper method that takes a sequence and returns a sequence of pairs that make up each item with it's previous item.

public static IEnumerable<Tuple<T, T>> Pair<T>(this IEnumerable<T> source)
{
    T previous;
    using (var iterator = source.GetEnumerator())
    {
        if (iterator.MoveNext())
            previous = iterator.Current;
        else
            yield break;

        while(iterator.MoveNext())
        {
            yield return Tuple.Create(previous, iterator.Current);
            previous = iterator.Current;
        }
    }
}

We'll also use this simple method to determine if two dates are in the same month:

public static bool AreSameMonth(DateTime first, DateTime second)
{
    return first.Year == second.Year 
        && first.Month == second.Month;
}

Using that, we can easily grab the month of each date and see if it's the month after the previous month. If it's true for all of the pairs, then we have consecutive months.

private static bool IsThisListConsecutive(IEnumerable<DateTime> orderedSlots)
{
    return orderedSlots.Pair()
        .All(pair => AreSameMonth(pair.Item1.AddMonths(1), pair.Item2));
}
like image 75
Servy Avatar answered Sep 24 '22 20:09

Servy


Note: This is completely untested, and the date checks are probably pretty bad or somewhat redundant, but that’s the best I could come up with right now ^^

public bool AreSameWeekdayEveryMonth(IEnumerable<DateTime> dates)
{
    var en = dates.GetEnumerator();
    if (en.MoveNext())
    {
        DayOfWeek weekday = en.Current.DayOfWeek;
        DateTime previous = en.Current;
        while (en.MoveNext())
        {
            DateTime d = en.Current;
            if (d.DayOfWeek != weekday || d.Day > 7)
                return false;
            if (d.Month != previous.Month && ((d - previous).Days == 28 || (d - previous).Days == 35))
                return false;
            previous = d;
        }
    }
    return true;
}
like image 39
poke Avatar answered Sep 23 '22 20:09

poke