9

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?

Andy Evans
  • 6,997
  • 18
  • 72
  • 118
  • How would a `Months` property work? How would it know which Month's # of days to use? After subtraction you're just left with a TimeSpan which is date-neutral and thus knows nothing about which months to use. – Kirk Woll Oct 08 '10 at 14:33
  • possible duplicate of [Difference in months](http://stackoverflow.com/questions/1525990/difference-in-months) – Kirk Woll Oct 08 '10 at 14:34
  • `.Days` returns the **number of days** in the interval, not the actual days. How do you define the fact that "*a month is between 2 dates*"? The month has **at least 1 day** in that interval? The month has **all days** in the interval? Also how do you need to represent a month using a `DateTime` struct? - as the 1st of the month? – CyberDude Oct 08 '10 at 14:35

4 Answers4

32

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.

Lasse Espeholt
  • 17,622
  • 5
  • 63
  • 99
  • 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)) – Rudean Feb 01 '22 at 13:55
4

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;
    }
Niloofar
  • 723
  • 8
  • 9
1

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();
Christian Hayter
  • 30,581
  • 6
  • 72
  • 99
  • 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 Feb 01 '22 at 13:08
1

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.

Dan Atkinson
  • 11,391
  • 14
  • 81
  • 114
Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • 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. – Dave Lucre Apr 18 '13 at 22:18
  • @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. – Jon Hanna May 30 '13 at 10:33