calculating the difference in months between two dates

Viewed 173417

In C#/.NET TimeSpan has TotalDays, TotalMinutes, etc. but I can't figure out a formula for total months difference. Variable days per month and leap years keep throwing me off. How can I get TotalMonths?

Edit Sorry for not being more clear: I know I can't actually get this from TimeSpan but I thought using TotalDays and TotalMinutes would be a good example to express what I was looking for ... except I'm trying to get Total Months.

Example: Dec 25, 2009 - Oct 6, 2009 = 2 TotalMonths. Oct 6th to Nov 5th equals 0 months. On Nov 6th, 1 month. On Dec 6th, 2 months

27 Answers

The accepted answer works perfectly when you want full months.

I needed partial months. This is the solution I came up with for partial months:

    /// <summary>
    /// Calculate the difference in months.
    /// This will round up to count partial months.
    /// </summary>
    /// <param name="lValue"></param>
    /// <param name="rValue"></param>
    /// <returns></returns>
    public static int MonthDifference(DateTime lValue, DateTime rValue)
    {
        var yearDifferenceInMonths = (lValue.Year - rValue.Year) * 12;
        var monthDifference = lValue.Month - rValue.Month;

        return yearDifferenceInMonths + monthDifference + 
            (lValue.Day > rValue.Day
                ? 1 : 0); // If end day is greater than start day, add 1 to round up the partial month
    }

I also needed a year difference with the same need for partial years. Here is the solution I came up with:

    /// <summary>
    /// Calculate the differences in years.
    /// This will round up to catch partial months.
    /// </summary>
    /// <param name="lValue"></param>
    /// <param name="rValue"></param>
    /// <returns></returns>
    public static int YearDifference(DateTime lValue, DateTime rValue)
    {
        return lValue.Year - rValue.Year +
               (lValue.Month > rValue.Month // Partial month, same year
                   ? 1
                   : ((lValue.Month = rValue.Month) 
                     && (lValue.Day > rValue.Day)) // Partial month, same year and month
                   ? 1 : 0);
    }

My take on this answer also uses an extension method, but it can return a positive or negative result.

public static int MonthsBefore(this DateTime dt1, DateTime dt2)
{
    (DateTime early, DateTime late, bool dt2After) = dt2 > dt1 ? (dt1,dt2,true) : (dt2,dt1,false);
    DateTime tmp; // Save the result so we don't repeat work
    int months = 1;
    while ((tmp = early.AddMonths(1)) <= late)
    {
        early = tmp;
        months++;
    }
    return (months-1)*(dt2After ? 1 : -1);
}

A couple tests:

// Just under 1 month's diff
Assert.AreEqual(0, new DateTime(2014, 1, 1).MonthsBefore(new DateTime(2014, 1, 31)));
// Just over 1 month's diff
Assert.AreEqual(1, new DateTime(2014, 1, 1).MonthsBefore(new DateTime(2014, 2, 2)));    
// Past date returns NEGATIVE
Assert.AreEqual(-6, new DateTime(2012, 1, 1).MonthsBefore(new DateTime(2011, 6, 10)));

Combing two of the answers above, another extension method is:

public static int ElapsedMonths(this DateTime date1, DateTime date2)
{
    DateTime earlierDate = (date1 > date2) ? date2 : date1;
    DateTime laterDate = (date1 > date2) ? date1 : date2;
    var eMonths = (laterDate.Month - earlierDate.Month) + 12 * (laterDate.Year - earlierDate.Year) - 
                                            ((earlierDate.Day > laterDate.Day) ? 1 : 0);
    return eMonths;
}

Thanks to @AdamRobinson and @MarkWhittaker

Here's how we did it:

int DifferenceInMonth(DateTime startDate, DateTime endDate) {
    long ToTicks(DateTime date) => new DateTimeOffset(date).Ticks;
    var daysPerMonth = 30.4;
    return (int)Math.Round((ToTicks(endDate) - ToTicks(startDate)) / TimeSpan.TicksPerDay / daysPerMonth);
}

The accepted answer is strongly incorrect:

For these dates: ldate = 2020-08-30 and rdate = 2020-08-01, we have one month, but the accepted answer returns 0.

For these dates: ldate = 2020-08-30 and rdate = 2020-10-01, we have three months, but the accepted answer returns -2.

Here is the correct method (maybe not the unique method, but correct) to calculate the quantity of months between two dates:

  • You don't have to check which date is lower than other.

  • An interval from the first day to the last day of month is counted as a month.

      public static int GetMontsBetween(DateTime date1, DateTime date2)
      {
          int monthCount = 0;
          int direction = date1 < date2 ? 1 : -1;
          date2 = date2.AddDays(direction);
    
          while (date1.Year != date2.Year || date1.Month != date2.Month)
          {
              date1 = date1.AddMonths(direction);
              monthCount++;
          }
    
          return monthCount;
      } 
    
Related