Method to return date ranges of 1 year I made a method that takes 2 DateTimes as a parameter, a startDate and a stopDate.

The routine should return a list of DateTime ranges by checking if the range in the parameters is above one year TimeSpan. If it is, it should separate the range into smaller ranges of one year, starting form startDate and adding a year until reaching the limit, and then adjusting the last range accordingly (as it might only contain a few months).

Can this method be made better or even recursive?

// startDate = 2016-01-01        
// endDate = 2020-06-01

List&lt;Tuple&lt;DateTime,DateTime&gt;&gt; list = GetYearsBetweenDates(startDate, endDate);

//list = 2016-01-01 2016-12-31 
//       2017-01-01 2017-12-31 
//       2018-01-01 2018-12-31 
//       2019-01-01 2019-12-31 
//       2020-01-01 2020-06-01

private List&lt;Tuple&lt;DateTime, DateTime&gt;&gt; GetYearsBetweenDates(DateTime startDate, DateTime stopDate)
{
    var list = new List&lt;Tuple&lt;DateTime, DateTime&gt;&gt;();
    var oneYear = TimeSpan.FromDays(365);
    var tempStopDate = startDate + oneYear;
    var tempStartDate = startDate;
    bool first = true;

    if (stopDate - startDate &lt; oneYear)
    {
        list.Add(new Tuple&lt;DateTime, DateTime&gt;(startDate, stopDate));
        return list;
    }

    while (tempStopDate != stopDate)
    {
        list.Add(new Tuple&lt;DateTime, DateTime&gt;(tempStartDate, tempStopDate));
        if (first)
        {
            tempStartDate += oneYear.Add(TimeSpan.FromDays(1)); // We should not have the same date twice
            first = false;
        }
        else
            tempStartDate += oneYear;

        tempStopDate += oneYear;

        if (tempStopDate &gt; stopDate)
        {
            tempStopDate = stopDate;
            list.Add(new Tuple&lt;DateTime, DateTime&gt;(tempStartDate, stopDate));
        }
    }

    return list;
}
If you perform all calcuclations dynamically your method becomes a simple few lines long loop:

private IEnumerable&lt;DateTimeRange&gt; GetYearsBetweenDates(DateTime startDate, DateTime stopDate)
{
    for (int i = startDate.Year; i &lt;= stopDate.Year; i++)
    {
        yield return new DateTimeRange
        (
            start: new DateTime(i, startDate.Month, startDate.Day),
            end:
             i == stopDate.Year 
             ? new DateTime(i, stopDate.Month, stopDate.Day).AddYears(1) 
             : new DateTime(i, startDate.Month, startDate.Day).AddYears(1)
        );
    }
}


So what I have I changed?

The method returns an IEnumerable&lt;T&gt; and uses the yield return which makes it deferred (this means it is executed only if enumerated).

The T is a new struct that is easier to understand than a Tuple:

struct DateTimeRange
{
    public DateTimeRange(DateTime start, DateTime end)
    {
        Start = start;
        End = end;
    }
    public DateTime Start { get; }
    public DateTime End { get; }
}


To get all dates you call it with ToList or ToArray

var dates = GetYearsBetweenDates(startDate, endDate).ToList();


or you put it in a foreach loop

foreach(var range in GetYearsBetweenDates(startDate, endDate))
{
    // do something
}




You can also exagerate and make it pure LINQ method without any manual loop but personaly I think the for loop looks better:

private IEnumerable&lt;DateTimeRange&gt; GetYearsBetweenDates3(DateTime startDate, DateTime stopDate)
{
    return Enumerable.Range(startDate.Year, stopDate.Year - startDate.Year + 1)
        .Select(x =&gt; new DateTimeRange
        (
            start: new DateTime(x, startDate.Month, startDate.Day),
            end:
             x == stopDate.Year 
             ? new DateTime(x, stopDate.Month, stopDate.Day).AddYears(1) 
             : new DateTime(x, startDate.Month, startDate.Day).AddYears(1)
        ));
}




What else?


var list = new List&lt;Tuple&lt;DateTime, DateTime&gt;&gt;();



You should always choose meaningful names for all variables. You did it well for the others. This could have been results or dates.


var oneYear = TimeSpan.FromDays(365);



It's safer to use the AddYear(1) method rather then hardcoding the number. Especially if you don't want to care about leapyears.