There is probably an easier way to do this, but this is what comes to me:
From your question, I will state that you need to group everything: from "the first Tuesday of February to the first Monday of March", etc., so that you get these "monthly" intervals, which are a variable number of days - depending on the month, which they start. If so, you really need to break it down into ranges using the day of the year to:
Group by the First Wednesday of the Month 2013 Group 0 (0-1) All DayOfYear between 0 and 1 2013 Group 1 (2-36) The first Wednesday of the month: January is DayOfYear 2. The first Wednesday of the month: February is DayOfYear 37. etc.
So, the first range is a function f such that f (32) = 1 (DayOfYear is 32), since it falls in the range from 2 to 37. This f is an indexed set of ranges, the item is in the collection, this DayOfYear falls in and returns this position index as the group number.
You can dynamically build this table by getting your minimum and maximum dates from GetDateCollection to determine the overall range. Since the logic related to dates is a rather complicated topic, I would drop out in a library like NodaTime (in particular arithmetic ), start from the min date, moving day by day until I find the first qualifying day (i.e. "first Monday of the month ") and create a range of 0 until this day - 1 as a group of 0 and push on the indexed collection (possibly ArrayList ). Then loop from that date using LocalDate.PlusWeeks(1) until the month changes by building a new range and not clicking that range on the same indexed collection.
Each time you switch to a new year, you will have to add 365 (or 366 if the previous year is a leap year) to your DayOfYear when creating your indexed collection, as DayOfYear is reset every year.
You now have a range set that acts like a table that groups days into the desired units based on their DayOfYear.
Write a function that intersects the table comparing DayOfYear ( + [365|366] * x , where x is the number of years you are comparing from your minimum year) of the given date against the items in the collection until you find a range this day gets inside and returns this index of this element as a group number. (Alternatively, each range can be Func<DateTime,bool> , which returns true if the provided DateTime falls into that range.)
An alternative data structure for collecting ranges will be an array with a length equal to all days from minimum to maximum dates in your date range, as well as the value for each day of their assigned group number (calculated with ranges as described above). This will work faster for grouping, although performance may not be noticeable if you are working with a smaller dataset (just a few hundred dates).