Create array of months between two dates

11,066

Solution 1

Try this:

static IEnumerable<DateTime> monthsBetween(DateTime d0, DateTime d1)
{
    return Enumerable.Range(0, (d1.Year - d0.Year) * 12 + (d1.Month - d0.Month + 1))
                     .Select(m => new DateTime(d0.Year, d0.Month, 1).AddMonths(m));
}

This includes both the starting month and the ending month. This finds how many months there is, and then creates a new DateTime based on d0´s year and month. That means the months are like yyyy-MM-01. If you want it to includes the time and day of d0 you can replace new DateTime(d0.Year, d0.Month, 1).AddMonths(m) by d0.AddMonths(m).

I see you need an array, in that case you just use monthsBetween(..., ...).ToArray() or put .ToArray() inside the method.

Solution 2

Since I just needed the year and month in between two dates I modified Lasse Espeholt answer a little. suppose: d0 = 2012-11-03

d1 = 2013-02-05

The result will be something like this:

2012-11

2012-12

2013-01

2013-02

 private List<Tuple<int,int>> year_month_Between(DateTime d0, DateTime d1)
    {
        List<DateTime> datemonth= Enumerable.Range(0, (d1.Year - d0.Year) * 12 + (d1.Month - d0.Month + 1))
                         .Select(m => new DateTime(d0.Year, d0.Month, 1).AddMonths(m)).ToList();
     List<Tuple<int, int>> yearmonth= new List<Tuple<int,int>>();

        foreach (DateTime x in datemonth)
        {
            yearmonth.Add(new Tuple<int, int>(x.Year, x.Month));
        }
        return yearmonth;
    }

Solution 3

Is this what you are looking for? The requirement is very ambiguous.

DateTime[] calendarMonthBoundaries = Enumerable.Range(0, 1 + endDate.Subtract(startDate).Days)
    .Select(offset => startDate.AddDays(offset))
    .Where(date => date.Day == 1)
    .ToArray();

Solution 4

You could enumerate increments of months with:

private static IEnumerable<DateTime> ByMonths(DateTime startDate, DateTime endDate)
{
  DateTime cur = startDate;

  for(int i = 0; cur <= endDate; cur = startDate.AddMonths(++i))
  {
    yield return cur;
  }
}

and then call ToArray() on that if you want an array. It's reasonably good about having values that are likely to be what is wanted; e.g. if you start at Jan 31st you'll next get Feb 28th (or 29th on leap years), then Mar 31st, then Apr 30th and so on.

Share:
11,066
Andy Evans
Author by

Andy Evans

old school developer trying to learn the new school.

Updated on July 21, 2022

Comments

  • Andy Evans
    Andy Evans almost 2 years

    I have the following snippet that I use to get the individual dates between two dates:

    DateTime[] output = Enumerable.Range(0, 1 + endDate.Subtract(startDate).Days)
        .Select(offset => startDate.AddDays(offset))
        .ToArray(); 
    

    However, the following section

    endDate.Subtract(startDate).Days
    

    does not have a .Months to return the months in the date range.

    For example, if I provide 1/1/2010 and 6/1/2010 I would expect to return 1/1/2010, 2/1/2010, 3/1/2010, 4/1/2010, 5/1/2010 and 6/1/2010.

    Any ideas?

  • Dave Lucre
    Dave Lucre about 11 years
    DateTime[] months = ByMonths({30/01/2013 12:00:00 AM}, {4/04/2013 12:00:00 AM}).ToArray(); This only returns 3 months (jan, feb, mar), April is missing.
  • Jon Hanna
    Jon Hanna almost 11 years
    @DaveLucre I'm not sure that's a bad thing, because I'm not sure just what the requirement in the question is considering "between". It could certainly be amended to include April in that case, I just don't know if it should.
  • Rudean
    Rudean over 2 years
    I actually like how simple this solution is! Just analyze all dates between start date and end date, but return only start month dates. Probably not the quickest solution but pretty straightforward.
  • Rudean
    Rudean over 2 years
    And if you want to get not months, but years, you can do it like this Enumerable.Range(0, (d1.Year - d0.Year) + 1) .Select(m => new DateTime(d0.Year, 1, 1).AddYears(m))