Loop months between a time span yyyy-mm and yyyy-mm I'm trying to come up with a more elegant solution for a loop in months that I wrote long time ago in C# 1.1 

I use a helper class Month but I'd prefer to get rid of it and make the code shorter and more readable.   

I receive a start period in format yyyy-mm and end period yyyy-mm and I need to execute something for every month between those 2 periods.

public void LoopMonths(string startM, string endM)
{
        //startM = "2015-02";
        //endM = "2018-11";

        int startYear = int.Parse(startM.Split('-')[0]);
        int startMonth = int.Parse(startM.Split('-')[1]);
        int endYear = int.Parse(endM.Split('-')[0]);
        int endMonth = int.Parse(endM.Split('-')[1]);

        Month month = new Month(startYear, startMonth);
        Month monthEnd = new Month(endYear, endMonth);

        while (month &lt;= monthEnd)
        {
            // do something ... 
            month = Month.NextMonth(month);
        }      
}


public class Month
{
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }

    public Month(int year, int month)
    {
        StartDate = new DateTime(year, month, 1);
        EndDate = new DateTime(year, month, DateTime.DaysInMonth(year, month));
    }

    public static Month NextMonth(Month month)
    {
        DateTime next = month.StartDate.AddMonths(1);
        return new Month(next.Year, next.Month);
    }

    public static bool operator &lt;=(Month month1, Month month2)
    {
        return month1.StartDate &lt;= month2.StartDate;
    }

    public static bool operator &gt;=(Month month1, Month month2)
    {
        return month1.StartDate &gt;= month2.StartDate;
    }
}
These are all good sugestions but to my taste not linq-ish enough and not really reusable. Since I don't like writing the same code serval times you might want to encapsulate some of this logic for later use.



You can extract two pieces. First you have a date-time range so create a Range struct. Here's a very simple one (as an example without any parameter validation - actually T should be IComparable so you can assure the range is valid).

readonly struct Range&lt;T&gt;
{
    public Range(T min, T max)
    {
        Min = min;
        Max = max;
    }

    public T Min { get; }

    public T Max { get; }
}


Then you are interpolating between min and max. Put this in an extension that will consume a Range and do the rest:

public static IEnumerable&lt;T&gt; Interpolate&lt;T&gt;(this Range&lt;T&gt; range, Func&lt;T, T&gt; next) where T : IComparable
{
    var current = range.Min;
    while (current.CompareTo(range.Max) &lt;= 0)
    {
        yield return (current = next(current));
    }
}


Now all you need is to parse the date so how about one more helper for that too?

static class Range
{
    public static Range&lt;DateTime&gt; FromDateTime(string min, string max, string format)
    {
        return new Range&lt;DateTime&gt;(
            DateTime.ParseExact(min, format, CultureInfo.InvariantCulture),
            DateTime.ParseExact(max, format, CultureInfo.InvariantCulture)
        );
    }
}


And we're ready to go. Create a range and let the extension work.

var range = Range.FromDateTime("2015-02", "2018-11", "yyyy-MM");
range.Interpolate(d =&gt; d.AddMonths(1)).Dump();


Now you have nice components that you can use in many more places and maybe in several projects.