By Rauf


2011-01-09 11:59:57 8 Comments

How to calculate the difference in months between two dates in C#?

Is there is equivalent of VB's DateDiff() method in C#. I need to find difference in months between two dates that are years apart. The documentation says that I can use TimeSpan like:

TimeSpan ts = date1 - date2;

but this gives me data in Days. I don't want to divide this number by 30 because not every month is 30 days and since the two operand values are quite apart from each other, I am afraid dividing by 30 might give me a wrong value.

Any suggestions?

30 comments

@Mircea Ion 2019-04-25 16:52:55

It seems that the DateTimeSpan solution pleases a lot of people. I don't know. Let's consider the:

BeginDate = 1972/2/29 EndDate = 1972/4/28.

The DateTimeSpan based answer is:

1 year(s), 2 month(s) and 0 day(s)

I implemented a method and based on that the answer is:

1 year(s), 1 month(s) and 28 day(s)

Clearly there are not 2 full months there. I would say that because we are at the end of the month of the begin date what's left is actually the full month of March plus the number of days passed in the month of the end date (April), so 1 month and 28 days.

If you read so far and you are intrigued I posted the method below. I am explaining in the comments the assumptions I make because how many months, the concept of months is such a moving target. Test it many times and see if the answers make sense. I usually choose test dates in adjacent years and once I verify an answer I move a day or two back and forth. So far it looks good, I'm sure you'll find some bugs :D. The code might look a bit rough but I hope it is clear enough:

static void Main(string[] args) {
        DateTime EndDate = new DateTime(1973, 4, 28);
        DateTime BeginDate = new DateTime(1972, 2, 29);
        int years, months, days;
        GetYearsMonthsDays(EndDate, BeginDate, out years, out months, out days);
        Console.WriteLine($"{years} year(s), {months} month(s) and {days} day(s)");
    }

    /// <summary>
    /// Calculates how many years, months and days are between two dates.
    /// </summary>
    /// <remarks>
    /// The fundamental idea here is that most of the time all of us agree
    /// that a month has passed today since the same day of the previous month.
    /// A particular case is when both days are the last days of their respective months 
    /// when again we can say one month has passed.
    /// In the following cases the idea of a month is a moving target.
    /// - When only the beginning date is the last day of the month then we're left just with 
    /// a number of days from the next month equal to the day of the month that end date represent
    /// - When only the end date is the last day of its respective month we clearly have a 
    /// whole month plus a few days after the the day of the beginning date until the end of its
    /// respective months
    /// In all the other cases we'll check
    /// - beginingDay > endDay -> less then a month just daysToEndofBeginingMonth + dayofTheEndMonth
    /// - beginingDay < endDay -> full month + (endDay - beginingDay)
    /// - beginingDay == endDay -> one full month 0 days
    /// 
    /// </remarks>
    /// 
    private static void GetYearsMonthsDays(DateTime EndDate, DateTime BeginDate, out int years, out int months, out int days ) {
        var beginMonthDays = DateTime.DaysInMonth(BeginDate.Year, BeginDate.Month);
        var endMonthDays = DateTime.DaysInMonth(EndDate.Year, EndDate.Month);
        // get the full years
        years = EndDate.Year - BeginDate.Year - 1;
        // how many full months in the first year
        var firstYearMonths = 12 - BeginDate.Month;
        // how many full months in the last year
        var endYearMonths = EndDate.Month - 1;
        // full months
        months = firstYearMonths + endYearMonths;           
        days = 0;
        // Particular end of month cases
        if(beginMonthDays == BeginDate.Day && endMonthDays == EndDate.Day) {
            months++;
        }
        else if(beginMonthDays == BeginDate.Day) {
            days += EndDate.Day;
        }
        else if(endMonthDays == EndDate.Day) {
            days += beginMonthDays - BeginDate.Day;
        }
        // For all the other cases
        else if(EndDate.Day > BeginDate.Day) {
            months++;
            days += EndDate.Day - BeginDate.Day;
        }
        else if(EndDate.Day < BeginDate.Day) {                
            days += beginMonthDays - BeginDate.Day;
            days += EndDate.Day;
        }
        else {
            months++;
        }
        if(months >= 12) {
            years++;
            months = months - 12;
        }
    }

@Edu Pelais 2019-03-28 16:19:46

My problem was solved with this solution:

static void Main(string[] args)
        {
            var date1 = new DateTime(2018, 12, 05);
            var date2 = new DateTime(2019, 03, 01);

            int CountNumberOfMonths() => (date2.Month - date1.Month) + 12 * (date2.Year - date1.Year);

            var numberOfMonths = CountNumberOfMonths();

            Console.WriteLine("Number of months between {0} and {1}: {2} months.", date1.ToString(), date2.ToString(), numberOfMonths.ToString());

            Console.ReadKey();

            //
            // *** Console Output:
            // Number of months between 05/12/2018 00:00:00 and 01/03/2019 00:00:00: 3 months.
            //

        }

@Tommix 2019-03-08 18:10:42

Simple and fast solution to count total months between 2 dates. If you want to get only different months, not counting the one that is in From date - just remove +1 from code.

public static int GetTotalMonths(DateTime From, DateTime Till)
        {
            int MonthDiff = 0;

            for (int i = 0; i < 12; i++)
            {
                if (From.AddMonths(i).Month == Till.Month)
                {
                    MonthDiff = i + 1;
                    break;
                }
            }

            return MonthDiff;
        }

@Dan Sutton 2019-01-07 19:10:08

Based on the excellent DateTimeSpan work done above, I've normalized the code a bit; this seems to work pretty well:

public class DateTimeSpan
{
  private DateTimeSpan() { }

  private DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
  {
    Years = years;
    Months = months;
    Days = days;
    Hours = hours;
    Minutes = minutes;
    Seconds = seconds;
    Milliseconds = milliseconds;
  }

  public int Years { get; private set; } = 0;
  public int Months { get; private set; } = 0;
  public int Days { get; private set; } = 0;
  public int Hours { get; private set; } = 0;
  public int Minutes { get; private set; } = 0;
  public int Seconds { get; private set; } = 0;
  public int Milliseconds { get; private set; } = 0;

  public static DateTimeSpan CompareDates(DateTime StartDate, DateTime EndDate)
  {
    if (StartDate.Equals(EndDate)) return new DateTimeSpan();
    DateTimeSpan R = new DateTimeSpan();
    bool Later;
    if (Later = StartDate > EndDate)
    {
      DateTime D = StartDate;
      StartDate = EndDate;
      EndDate = D;
    }

    // Calculate Date Stuff
    for (DateTime D = StartDate.AddYears(1); D < EndDate; D = D.AddYears(1), R.Years++) ;
    if (R.Years > 0) StartDate = StartDate.AddYears(R.Years);
    for (DateTime D = StartDate.AddMonths(1); D < EndDate; D = D.AddMonths(1), R.Months++) ;
    if (R.Months > 0) StartDate = StartDate.AddMonths(R.Months);
    for (DateTime D = StartDate.AddDays(1); D < EndDate; D = D.AddDays(1), R.Days++) ;
    if (R.Days > 0) StartDate = StartDate.AddDays(R.Days);

    // Calculate Time Stuff
    TimeSpan T1 = EndDate - StartDate;
    R.Hours = T1.Hours;
    R.Minutes = T1.Minutes;
    R.Seconds = T1.Seconds;
    R.Milliseconds = T1.Milliseconds;

    // Return answer. Negate values if the Start Date was later than the End Date
    if (Later)
      return new DateTimeSpan(-R.Years, -R.Months, -R.Days, -R.Hours, -R.Minutes, -R.Seconds, -R.Milliseconds);
    return R;
  }
}

@Bassie 2019-02-19 11:16:00

When comparing with CompareDates(x, y) where x={01/02/2019 00:00:00} and y={01/05/2020 00:00:00} then Months gives me 2

@Kirk Woll 2012-02-09 18:14:05

Here is a comprehensive solution to return a DateTimeSpan, similar to a TimeSpan, except that it includes all the date components in addition to the time components.

Usage:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    var dateSpan = DateTimeSpan.CompareDates(compareTo, now);
    Console.WriteLine("Years: " + dateSpan.Years);
    Console.WriteLine("Months: " + dateSpan.Months);
    Console.WriteLine("Days: " + dateSpan.Days);
    Console.WriteLine("Hours: " + dateSpan.Hours);
    Console.WriteLine("Minutes: " + dateSpan.Minutes);
    Console.WriteLine("Seconds: " + dateSpan.Seconds);
    Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds);
}

Outputs:

Years: 1
Months: 5
Days: 27
Hours: 1
Minutes: 36
Seconds: 50
Milliseconds: 0

For convenience, I've lumped the logic into the DateTimeSpan struct, but you may move the method CompareDates wherever you see fit. Also note, it doesn't matter which date comes before the other.

public struct DateTimeSpan
{
    public int Years { get; }
    public int Months { get; }
    public int Days { get; }
    public int Hours { get; }
    public int Minutes { get; }
    public int Seconds { get; }
    public int Milliseconds { get; }

    public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
    {
        Years = years;
        Months = months;
        Days = days;
        Hours = hours;
        Minutes = minutes;
        Seconds = seconds;
        Milliseconds = milliseconds;
    }

    enum Phase { Years, Months, Days, Done }

    public static DateTimeSpan CompareDates(DateTime date1, DateTime date2)
    {
        if (date2 < date1)
        {
            var sub = date1;
            date1 = date2;
            date2 = sub;
        }

        DateTime current = date1;
        int years = 0;
        int months = 0;
        int days = 0;

        Phase phase = Phase.Years;
        DateTimeSpan span = new DateTimeSpan();
        int officialDay = current.Day;

        while (phase != Phase.Done)
        {
            switch (phase)
            {
                case Phase.Years:
                    if (current.AddYears(years + 1) > date2)
                    {
                        phase = Phase.Months;
                        current = current.AddYears(years);
                    }
                    else
                    {
                        years++;
                    }
                    break;
                case Phase.Months:
                    if (current.AddMonths(months + 1) > date2)
                    {
                        phase = Phase.Days;
                        current = current.AddMonths(months);
                        if (current.Day < officialDay && officialDay <= DateTime.DaysInMonth(current.Year, current.Month))
                            current = current.AddDays(officialDay - current.Day);
                    }
                    else
                    {
                        months++;
                    }
                    break;
                case Phase.Days:
                    if (current.AddDays(days + 1) > date2)
                    {
                        current = current.AddDays(days);
                        var timespan = date2 - current;
                        span = new DateTimeSpan(years, months, days, timespan.Hours, timespan.Minutes, timespan.Seconds, timespan.Milliseconds);
                        phase = Phase.Done;
                    }
                    else
                    {
                        days++;
                    }
                    break;
            }
        }

        return span;
    }
}

@Deeptechtons 2012-11-26 03:36:30

@KirkWoll thanks. But why is that DateTimeSpan returns 34 days for this date time difference actually it is 35 timeanddate.com/date/…

@Kirk Woll 2012-11-26 14:09:30

@Deeptechtons, nice catch. There were a couple issues you've brought to my attention, both having to do with the start date is 31 and the date "passes through" months with fewer days. I've inverted the logic (so that it goes from early to later than vice versa) and now accumulates the months without modifying the current date (and thus passing through in-between months with fewer days) Still not entirely sure what the ideal result should be when comparing 10/31/2012 to 11/30/2012. Right now the result is 1 month.

@Deeptechtons 2012-11-27 04:16:48

@KirkWoll thanks for the update, maybe i got few more gotchas let me affirm it after some tests Good Job :)

@jwg 2013-08-21 09:51:52

I wrote an answer stackoverflow.com/a/17537472/1737957 to a similar question which tested proposed answers (and found that most of them don't work). This answer is one of the few that does work (according to my test suite). Link to github on my answer.

@Enigmativity 2015-06-03 09:29:42

@KirkWoll - This answer doesn't appear to work for edge cases where the from date has a day value higher than the to date's month or where the source date is a leap day. Try 2020-02-29 to 2021-06-29 - it returns "1y 4m 1d", but the value should be "1y 4m 0d", right?

@Kirk Woll 2016-04-02 21:45:28

@Enigmativity, thanks for your comments. I've updated my answer by handling this scenario in the Phase.Months section. Seems to work for me.

@Gone Coding 2016-04-19 09:40:15

Very cool, but please note this algorithm has some edge-case issues. If you happen to use DateTime.MinValue or DateTime.MaxValuein date values this will fall over. e.g. System.ArgumentOutOfRangeException': "The added or subtracted value results in an un-representable DateTime."

@Patrick Oniel Bernardo 2018-11-15 07:07:18

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {

        label3.Text = new DateDifference(Convert.ToDateTime("2018-09-13"), Convert.ToDateTime("2018-11-15")).ToString();
        label2.Text = new DateDifference(Convert.ToDateTime("2018-10-12"), Convert.ToDateTime("2018-11-15")).ToString();

        DateDifference oDateDifference = new DateDifference(Convert.ToDateTime("2018-11-12"));
       label1.Text  =   oDateDifference.ToString();

    }
}




public class DateDifference
{
    public DateTime start { get; set; }
    public DateTime currentDAte { get; set; }
    public DateTime origstart { get; set; }
    public DateTime origCurrentDAte { get; set; }

    int days { get; set; }
    int months { get; set; }
    int years { get; set; }

    public DateDifference(DateTime postedDate, DateTime currentDAte)
    {
        this.start = this.removeTime(postedDate);
        this.currentDAte = this.removeTime(currentDAte);
        this.origstart = postedDate;
        this.origCurrentDAte = currentDAte;

    }

    public DateDifference(DateTime postedDate)
    {
        DateTime currentDate_ = DateTime.Now;
        this.start = this.removeTime(postedDate);
        this.currentDAte = this.removeTime(currentDate_);
        this.origstart = postedDate;
        this.origCurrentDAte = currentDate_;
        if (start > this.currentDAte)
        {
            throw new Exception("Current date is greater than date posted");
        }
        this.compute();
    }

    void compute()
    {
        while (this.start.Year <= this.currentDAte.Year)
        {
            if (this.start.Year <= this.currentDAte.Year && (this.start.AddMonths(1) <= this.currentDAte))
            {
                ++this.months;
                this.start = this.start.AddMonths(1);
            }

            if ((this.start.Year == this.currentDAte.Year) && (this.start >= this.currentDAte.AddMonths(-1) && this.start <= this.currentDAte))
            {
                break;
            }
        }

        while (this.start.DayOfYear < this.currentDAte.DayOfYear)
        {
            ++this.days;
            this.start = start.AddDays(1);
        }

        if (this.months > 11)
        {
            while (this.months > 11)
            {
                ++this.years;
                this.months = months - 12;
            }
        }

    }


    public override string ToString()
    {
        if (this.start > this.currentDAte)
        {
            throw new Exception("Current date is greater than date posted");
        }
        String ret = this.ComposeTostring();
        this.reset();
        return ret;
    }

    private String ComposeTostring()
    {
        this.compute();
        if (this.years > 0)
        {
            if (this.months > 0)
            {
                if (this.days > 0)
                {
                    return String.Format("{0} year{1}, {2} month{3} && {4} Day{5} ago", this.years, plural(this.years), this.months, plural(this.months), this.days, plural(this.days));
                }
                return String.Format("{0} year{1}, {2} month{3} ago", this.years, plural(this.years), this.months, plural(this.months));
            }
            else
            {
                if (this.days > 0)
                {
                    return String.Format("{0} year{1},{2} day{3} ago", this.years, plural(this.years), this.days, plural(this.days));
                }

                return String.Format("{0} year{1} ago", this.years, plural(this.years));

            }
        }

        if (this.months > 0)
        {
            if (this.days > 0)
            {
                return String.Format("{0} month{1}, {2} day{3} ago", this.months, plural(this.months), this.days, plural(this.days));
            }
            else
            {
                return String.Format("{0} month{1} ago", this.months, plural(this.months));
            }
        }

        if ((this.origCurrentDAte - this.origstart).Days > 0)
        {
            int daysDiff = (this.origCurrentDAte - this.origstart).Days;
            this.origstart = this.origstart.AddDays(daysDiff);
            int HoursDiff = (this.origCurrentDAte - this.origstart).Hours;
            return String.Format("{0} day{1}, {2} hour{3} ago", daysDiff, plural(daysDiff), HoursDiff, plural(HoursDiff));

        }
        else if ((this.origCurrentDAte - this.origstart).Hours > 0)
        {
            int HoursDiff = (this.origCurrentDAte - this.origstart).Hours;
            this.origstart = this.origstart.AddHours(HoursDiff);
            int MinDiff = (this.origCurrentDAte - this.origstart).Minutes;
            return String.Format("{0} hour{1}, {2} minute{3} ago", HoursDiff, plural(HoursDiff), MinDiff, plural(MinDiff));
        }
        else if ((this.origCurrentDAte - this.origstart).Minutes > 0)
        {

            int MinDiff = (this.origCurrentDAte - this.origstart).Minutes;
            this.origstart = this.origstart.AddMinutes(MinDiff);
            int SecDiff = (this.origCurrentDAte - this.origstart).Seconds;
            return String.Format("{0} minute{1}, {2} second{3} ago", MinDiff, plural(MinDiff), SecDiff, plural(SecDiff));
        }
        else if ((this.origCurrentDAte - this.origstart).Seconds > 0)
        {
            int sec = (this.origCurrentDAte - this.origstart).Seconds;
            return String.Format("{0} second{1}", sec, plural(sec));
        }

        return "";
    }

    String plural(int val)
    {
        return (val > 1 ? "s" : String.Empty);
    }

    DateTime removeTime(DateTime dtime)
    {
        dtime = dtime.AddHours(-dtime.Hour);
        dtime = dtime.AddMinutes(-dtime.Minute);
        dtime = dtime.AddSeconds(-dtime.Second);
        return dtime;
    }

    public void reset()
    {

        this.days = 0;
        this.months = 0;
        this.years = 0;
        this.start = DateTime.MinValue;
        this.currentDAte = DateTime.MinValue;
        this.origstart = DateTime.MinValue;
        this.origCurrentDAte = DateTime.MinValue;
    }
}

@Shahnawaz Alam 2018-06-01 09:46:16

Simple fix. Works 100%

        var exactmonth = (date1.Year - date2.Year) * 12 + date1.Month - 
        date2.Month +  (date1.Day >= date2.Day ? 0 : -1);
        Console.WriteLine(exactmonth);

@JeffC 2018-06-01 13:47:31

This is an exact copy of DrunkCoder's code from this comment 5 years ago. stackoverflow.com/questions/4638993/…

@Simon Mourier 2016-08-19 17:24:27

Here is a simple solution that works at least for me. It's probably not the fastest though because it uses the cool DateTime's AddMonth feature in a loop:

public static int GetMonthsDiff(DateTime start, DateTime end)
{
    if (start > end)
        return GetMonthsDiff(end, start);

    int months = 0;
    do
    {
        start = start.AddMonths(1);
        if (start > end)
            return months;

        months++;
    }
    while (true);
}

@GreatNate 2014-01-07 18:50:52

There are not a lot of clear answers on this because you are always assuming things.

This solution calculates between two dates the months between assuming you want to save the day of month for comparison, (meaning that the day of the month is considered in the calculation)

Example, if you have a date of 30 Jan 2012, 29 Feb 2012 will not be a month but 01 March 2013 will.

It's been tested pretty thoroughly, probably will clean it up later as we use it, but here:

private static int TotalMonthDifference(DateTime dtThis, DateTime dtOther)
{
    int intReturn = 0;
    bool sameMonth = false;

    if (dtOther.Date < dtThis.Date) //used for an error catch in program, returns -1
        intReturn--;

    int dayOfMonth = dtThis.Day; //captures the month of day for when it adds a month and doesn't have that many days
    int daysinMonth = 0; //used to caputre how many days are in the month

    while (dtOther.Date > dtThis.Date) //while Other date is still under the other
    {
        dtThis = dtThis.AddMonths(1); //as we loop, we just keep adding a month for testing
        daysinMonth = DateTime.DaysInMonth(dtThis.Year, dtThis.Month); //grabs the days in the current tested month

        if (dtThis.Day != dayOfMonth) //Example 30 Jan 2013 will go to 28 Feb when a month is added, so when it goes to march it will be 28th and not 30th
        {
            if (daysinMonth < dayOfMonth) // uses day in month max if can't set back to day of month
                dtThis.AddDays(daysinMonth - dtThis.Day);
            else
                dtThis.AddDays(dayOfMonth - dtThis.Day);
        }
        if (((dtOther.Year == dtThis.Year) && (dtOther.Month == dtThis.Month))) //If the loop puts it in the same month and year
        {
            if (dtOther.Day >= dayOfMonth) //check to see if it is the same day or later to add one to month
                intReturn++;
            sameMonth = true; //sets this to cancel out of the normal counting of month
        }
        if ((!sameMonth)&&(dtOther.Date > dtThis.Date))//so as long as it didn't reach the same month (or if i started in the same month, one month ahead, add a month)
            intReturn++;
    }
    return intReturn; //return month
}

@George Mavritsakis 2015-10-02 10:34:52

My understanding of the total months difference between 2 dates has an integral and a fractional part (the date matters).

The integral part is the full months difference.

The fractional part, for me, is the difference of the % of the day (to the full days of month) between the starting and ending months.

public static class DateTimeExtensions
{
    public static double TotalMonthsDifference(this DateTime from, DateTime to)
    {
        //Compute full months difference between dates
        var fullMonthsDiff = (to.Year - from.Year)*12 + to.Month - from.Month;

        //Compute difference between the % of day to full days of each month
        var fractionMonthsDiff = ((double)(to.Day-1) / (DateTime.DaysInMonth(to.Year, to.Month)-1)) -
            ((double)(from.Day-1)/ (DateTime.DaysInMonth(from.Year, from.Month)-1));

        return fullMonthsDiff + fractionMonthsDiff;
    }
}

With this extension, those are the results:

2/29/2000 TotalMonthsDifference 2/28/2001 => 12
2/28/2000 TotalMonthsDifference 2/28/2001 => 12.035714285714286
01/01/2000 TotalMonthsDifference 01/16/2000 => 0.5
01/31/2000 TotalMonthsDifference 01/01/2000 => -1.0
01/31/2000 TotalMonthsDifference 02/29/2000 => 1.0
01/31/2000 TotalMonthsDifference 02/28/2000 => 0.9642857142857143
01/31/2001 TotalMonthsDifference 02/28/2001 => 1.0

@jenson-button-event 2014-12-06 14:01:44

I just needed something simple to cater for e.g. employment dates where only the month/year is entered, so wanted distinct years and months worked in. This is what I use, here for usefullness only

public static YearsMonths YearMonthDiff(DateTime startDate, DateTime endDate) {
    int monthDiff = ((endDate.Year * 12) + endDate.Month) - ((startDate.Year * 12) + startDate.Month) + 1;
    int years = (int)Math.Floor((decimal) (monthDiff / 12));
    int months = monthDiff % 12;
    return new YearsMonths {
        TotalMonths = monthDiff,
            Years = years,
            Months = months
    };
}

.NET Fiddle

@Saeed Mahmoudi 2015-11-07 11:20:22

The most precise way is this that return difference in months by fraction :

private double ReturnDiffereceBetweenTwoDatesInMonths(DateTime startDateTime, DateTime endDateTime)
{
    double result = 0;
    double days = 0;
    DateTime currentDateTime = startDateTime;
    while (endDateTime > currentDateTime.AddMonths(1))
    {
        result ++;

        currentDateTime = currentDateTime.AddMonths(1);
    }

    if (endDateTime > currentDateTime)
    {
        days = endDateTime.Subtract(currentDateTime).TotalDays;

    }
    return result + days/endDateTime.GetMonthDays;
}

@reza akhlaghi 2013-09-30 07:28:30

I wrote a function to accomplish this, because the others ways weren't working for me.

public string getEndDate (DateTime startDate,decimal monthCount)
{
    int y = startDate.Year;
    int m = startDate.Month;

    for (decimal  i = monthCount; i > 1; i--)
    {
        m++;
        if (m == 12)
        { y++;
            m = 1;
        }
    }
    return string.Format("{0}-{1}-{2}", y.ToString(), m.ToString(), startDate.Day.ToString());
}

@kleopatra 2013-09-30 07:36:24

Please answer in English (vs any invented language ...)

@TabbyCool 2014-04-15 15:44:33

Why not just do startDate.AddMonths(monthCount).ToShortDateString()? This doesn't answer the original question that was asked anyway!

@reza akhlaghi 2014-04-19 05:29:03

oh, sorry @TabbyCool , this code works good in my program! programmers rule says: first code works and then optimization! tanx for ur comment :)

@Guillaume86 2012-03-26 14:58:14

If you want the exact number of full months, always positive (2000-01-15, 2000-02-14 returns 0), considering a full month is when you reach the same day the next month (something like the age calculation)

public static int GetMonthsBetween(DateTime from, DateTime to)
{
    if (from > to) return GetMonthsBetween(to, from);

    var monthDiff = Math.Abs((to.Year * 12 + (to.Month - 1)) - (from.Year * 12 + (from.Month - 1)));

    if (from.AddMonths(monthDiff) > to || to.Day < from.Day)
    {
        return monthDiff - 1;
    }
    else
    {
        return monthDiff;
    }
}

Edit reason: the old code was not correct in some cases like :

new { From = new DateTime(1900, 8, 31), To = new DateTime(1901, 8, 30), Result = 11 },

Test cases I used to test the function:

var tests = new[]
{
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 1, 1), Result = 0 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 1, 2), Result = 0 },
    new { From = new DateTime(1900, 1, 2), To = new DateTime(1900, 1, 1), Result = 0 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 2, 1), Result = 1 },
    new { From = new DateTime(1900, 2, 1), To = new DateTime(1900, 1, 1), Result = 1 },
    new { From = new DateTime(1900, 1, 31), To = new DateTime(1900, 2, 1), Result = 0 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1900, 9, 30), Result = 0 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1900, 10, 1), Result = 1 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1901, 1, 1), Result = 12 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1911, 1, 1), Result = 132 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1901, 8, 30), Result = 11 },
};

@Cristian Badila 2015-12-16 17:58:01

Just so as to avoid confusion for other people, I think this solution is not correct. Using the test case: new { From = new DateTime(2015, 12, 31), To = new DateTime(2015, 6, 30), Result = 6 } the test will fail as the result is 5.

@Cristian Badila 2015-12-16 18:57:58

Added a quick gist with the fix I propose here

@Guillaume86 2015-12-17 16:48:47

I'm not sure I get it, my function returns 6 as it should: dotnetfiddle.net/MRZNnC

@Cristian Badila 2015-12-18 13:13:08

I copied the test case here by hand and It has a mistake. The failing spec should be: new { From = new DateTime(2015, 12, 31), To = new DateTime(2016, 06, 30), Result = 6 }. The "bug" lies in the to.Day < from.Day code which doesn't take into account that months can end in a different "day of the month". In this case from December 31st 2015, until June 30 2016, 6 complete months will have passed (since June has 30 days) but your code would return 5.

@Guillaume86 2015-12-18 15:32:18

It's expected behavior in my opinion, well or it's the behavior I do expect at least. I precised a complete month is when you reach the same day (or the next month like in this case).

@Cristian Badila 2015-12-18 17:01:55

I understand, that's why I said that "I think the solution is not correct". I still tried to offer an alternative which results in less confusion. In my mind a month is a calendar subunit with a variable number of days and it makes sense to consider a month complete when it's last day is reached. As another example (taking into account February can have 28/29 days) using your code the difference between 2016, 2, 29 and 2017, 2, 28 would be 11 months which to me is "surprising".

@Guillaume86 2015-12-18 17:53:26

Well I guess it's a just a matter of preference. I was also going to mention the leap day case to justify my choice but it's not universal either. There's countries that have set the rule for leap day birthdays in one way and some the other, I side with UK in this case: en.wikipedia.org/wiki/February_29#Legal_status .

@Patrice Calvé 2013-10-16 16:08:29

There's 3 cases: same year, previous year and other years.

If the day of the month does not matter...

public int GetTotalNumberOfMonths(DateTime start, DateTime end)
{
    // work with dates in the right order
    if (start > end)
    {
        var swapper = start;
        start = end;
        end = swapper;
    }

    switch (end.Year - start.Year)
    {
        case 0: // Same year
            return end.Month - start.Month;

        case 1: // last year
            return (12 - start.Month) + end.Month;

        default:
            return 12 * (3 - (end.Year - start.Year)) + (12 - start.Month) + end.Month;
    }
}

@Elmer 2013-05-09 17:57:58

This worked for what I needed it for. The day of month didn't matter in my case because it always happens to be the last day of the month.

public static int MonthDiff(DateTime d1, DateTime d2){
    int retVal = 0;

    if (d1.Month<d2.Month)
    {
        retVal = (d1.Month + 12) - d2.Month;
        retVal += ((d1.Year - 1) - d2.Year)*12;
    }
    else
    {
        retVal = d1.Month - d2.Month;
        retVal += (d1.Year - d2.Year)*12;
    }
    //// Calculate the number of years represented and multiply by 12
    //// Substract the month number from the total
    //// Substract the difference of the second month and 12 from the total
    //retVal = (d1.Year - d2.Year) * 12;
    //retVal = retVal - d1.Month;
    //retVal = retVal - (12 - d2.Month);

    return retVal;
}

@Sukanta 2013-02-12 20:54:57

public static int PayableMonthsInDuration(DateTime StartDate, DateTime EndDate)
{
    int sy = StartDate.Year; int sm = StartDate.Month; int count = 0;
    do
    {
        count++;if ((sy == EndDate.Year) && (sm >= EndDate.Month)) { break; }
        sm++;if (sm == 13) { sm = 1; sy++; }
    } while ((EndDate.Year >= sy) || (EndDate.Month >= sm));
    return (count);
}

This solution is for Rental/subscription calculation, where difference doesn't means to be subtraction, it's meant to be the span in within those two dates.

@Ahmed 2018-02-13 11:43:56

In my case it is required to calculate the complete month from the start date to the day prior to this day in the next month or from start to end of month.


Ex: from 1/1/2018 to 31/1/2018 is a complete month
Ex2: from 5/1/2018 to 4/2/2018 is a complete month

so based on this here is my solution:

public static DateTime GetMonthEnd(DateTime StartDate, int MonthsCount = 1)
{
    return StartDate.AddMonths(MonthsCount).AddDays(-1);
}
public static Tuple<int, int> CalcPeriod(DateTime StartDate, DateTime EndDate)
{
    int MonthsCount = 0;
    Tuple<int, int> Period;
    while (true)
    {
        if (GetMonthEnd(StartDate) > EndDate)
            break;
        else
        {
            MonthsCount += 1;
            StartDate = StartDate.AddMonths(1);
        }
    }
    int RemainingDays = (EndDate - StartDate).Days + 1;
    Period = new Tuple<int, int>(MonthsCount, RemainingDays);
    return Period;
}

Usage:

Tuple<int, int> Period = CalcPeriod(FromDate, ToDate);

Note: in my case it was required to calculate the remaining days after the complete months so if it's not your case you could ignore the days result or even you could change the method return from tuple to integer.

@Adam Ralph 2011-01-09 12:15:32

Assuming the day of the month is irrelevant (i.e. the diff between 2011.1.1 and 2010.12.31 is 1), with date1 > date2 giving a positive value and date2 > date1 a negative value

((date1.Year - date2.Year) * 12) + date1.Month - date2.Month

Or, assuming you want an approximate number of 'average months' between the two dates, the following should work for all but very huge date differences.

date1.Subtract(date2).Days / (365.25 / 12)

Note, if you were to use the latter solution then your unit tests should state the widest date range which your application is designed to work with and validate the results of the calculation accordingly.


Update (with thanks to Gary)

If using the 'average months' method, a slightly more accurate number to use for the 'average number of days per year' is 365.2425.

@Kurru 2011-01-09 12:34:53

Why wouldn't this work for huge date differences?

@Adam Ralph 2011-01-09 12:40:56

@Kurru - 365 / 12 is only an approximate measure of the average length of a month in days. It is an inaccurate measure. For small date ranges this inaccuracy can be tolerated but for very huge date ranges this inaccuracy may become significant.

@Kurru 2011-01-09 12:44:03

Ahhh forgot about the variable month thing. +1

@Adam Ralph 2011-01-09 12:49:08

@Kurru - However, it is also worth pointing out if this 'average month' number is indeed what is being sought after then it is likely that it will be used in a calculation which itself will be an approximation which may mean that the inaccuracy is not significant. We would need to know the intended usage of the result in order to judge this.

@Roman Starkov 2011-01-09 13:06:48

Adam, the way I read the question, what is being sought after is your first code snippet. Was about to post it myself.

@DrunkCoder 2012-11-21 22:04:08

I think it is necessary to consider Day component. Something like this (date1.Year - date2.Year) * 12 + date1.Month - date2.Month + (date1.Day >= date2.Day ? 0 : -1)

@Adam Ralph 2012-11-23 07:32:27

@DrunkCoder it depends on the requirements of a given system. In some cases your solution may indeed be the best choice. E.g. it's important to consider what happens when two dates span a 31 day month, a 30 day month, a 28 day February or a 29 day February. If the results of your formula deliver what the system requires then it's clearly the right choice. If not, then something else is required.

@Binary Worrier 2013-09-30 07:53:19

To second what Adam said, I spent years writing code for Acturaries. Some calculations were divide by number of days, round up by 30 to get monthly figure. Sometimes counting months assumed every date starts on the first of the month, count whole months accordingly. There is no best method when it comes to calculating dates. Unless you are the customer you're writing code for, push this back up the chain and get it clarified, possibly by you customers accountant.

@Gary 2015-09-22 20:39:03

365.2425 is slightly more accurate number of days in a Gregorian Calendar, if that is what you are using. However, by DateTime.MaxValue (January 1, 10000) that's only about 59 days difference. Also, the definition of a year can be much different depending on your perspective en.wikipedia.org/wiki/Year.

@Adam Ralph 2015-09-23 21:13:53

Thanks @Gary, I wonder if should update my answer to use 365.2425. It's a cheap change and does indeed improve the accuracy.

@Adam Ralph 2015-09-24 06:52:35

Added an update

@Tjad Clark 2017-12-12 11:12:09

Note that the first solution is invalid if one is asking for a date range that lapses over December to January, but doesn't actually complete a year. i.e: Sep 2017 - February 2018 would provide incorrect result

@Adam Ralph 2017-12-12 18:13:08

@TjadClark I just tried the first solution for the dates you mention and it gave me the expected answer of 5 months.

@Tjad Clark 2017-12-13 08:08:53

Apologies, you are correct!

@John A 2017-04-21 15:33:26

This is in response to Kirk Woll's answer. I don't have enough reputation points to reply to a comment yet...

I liked Kirk's solution and was going to shamelessly rip it off and use it in my code, but when I looked through it I realized it's way too complicated. Unnecessary switching and looping, and a public constructor that is pointless to use.

Here's my rewrite:

public class DateTimeSpan {
    private DateTime _date1;
    private DateTime _date2;
    private int _years;
    private int _months;
    private int _days;
    private int _hours;
    private int _minutes;
    private int _seconds;
    private int _milliseconds;

    public int Years { get { return _years; } }
    public int Months { get { return _months; } }
    public int Days { get { return _days; } }
    public int Hours { get { return _hours; } }
    public int Minutes { get { return _minutes; } }
    public int Seconds { get { return _seconds; } }
    public int Milliseconds { get { return _milliseconds; } }

    public DateTimeSpan(DateTime date1, DateTime date2) {
        _date1 = (date1 > date2) ? date1 : date2;
        _date2 = (date2 < date1) ? date2 : date1;

        _years = _date1.Year - _date2.Year;
        _months = (_years * 12) + _date1.Month - _date2.Month;
        TimeSpan t = (_date2 - _date1);
        _days = t.Days;
        _hours = t.Hours;
        _minutes = t.Minutes;
        _seconds = t.Seconds;
        _milliseconds = t.Milliseconds;

    }

    public static DateTimeSpan CompareDates(DateTime date1, DateTime date2) {
        return new DateTimeSpan(date1, date2);
    }
}

Usage1, pretty much the same:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    var dateSpan = new DateTimeSpan(compareTo, now);
    Console.WriteLine("Years: " + dateSpan.Years);
    Console.WriteLine("Months: " + dateSpan.Months);
    Console.WriteLine("Days: " + dateSpan.Days);
    Console.WriteLine("Hours: " + dateSpan.Hours);
    Console.WriteLine("Minutes: " + dateSpan.Minutes);
    Console.WriteLine("Seconds: " + dateSpan.Seconds);
    Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds);
}

Usage2, similar:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    Console.WriteLine("Years: " + DateTimeSpan.CompareDates(compareTo, now).Years);
    Console.WriteLine("Months: " + DateTimeSpan.CompareDates(compareTo, now).Months);
    Console.WriteLine("Days: " + DateTimeSpan.CompareDates(compareTo, now).Days);
    Console.WriteLine("Hours: " + DateTimeSpan.CompareDates(compareTo, now).Hours);
    Console.WriteLine("Minutes: " + DateTimeSpan.CompareDates(compareTo, now).Minutes);
    Console.WriteLine("Seconds: " + DateTimeSpan.CompareDates(compareTo, now).Seconds);
    Console.WriteLine("Milliseconds: " + DateTimeSpan.CompareDates(compareTo, now).Milliseconds);
}

@Morgs 2016-08-29 09:37:25

Here is my contribution to get difference in Months that I've found to be accurate:

namespace System
{
     public static class DateTimeExtensions
     {
         public static Int32 DiffMonths( this DateTime start, DateTime end )
         {
             Int32 months = 0;
             DateTime tmp = start;

             while ( tmp < end )
             {
                 months++;
                 tmp = tmp.AddMonths( 1 );
             }

             return months;
        }
    }
}

Usage:

Int32 months = DateTime.Now.DiffMonths( DateTime.Now.AddYears( 5 ) );

You can create another method called DiffYears and apply exactly the same logic as above and AddYears instead of AddMonths in the while loop.

@Chethaka Wickramarathne 2016-08-10 10:31:13

LINQ Solution,

DateTime ToDate = DateTime.Today;
DateTime FromDate = ToDate.Date.AddYears(-1).AddDays(1);

int monthCount = Enumerable.Range(0, 1 + ToDate.Subtract(FromDate).Days)
                    .Select(x => FromDate.AddDays(x))
                    .ToList<DateTime>()
                    .GroupBy(z => new { z.Year, z.Month })
                    .Count();

@Brent 2016-04-29 14:48:16

Here's a much more concise solution using VB.Net DateDiff for Year, Month, Day only. You can load the DateDiff library in C# as well.

date1 must be <= date2

VB.NET

Dim date1 = Now.AddDays(-2000)
Dim date2 = Now
Dim diffYears = DateDiff(DateInterval.Year, date1, date2) - If(date1.DayOfYear > date2.DayOfYear, 1, 0)
Dim diffMonths = DateDiff(DateInterval.Month, date1, date2) - diffYears * 12 - If(date1.Day > date2.Day, 1, 0)
Dim diffDays = If(date2.Day >= date1.Day, date2.Day - date1.Day, date2.Day + (Date.DaysInMonth(date1.Year, date1.Month) - date1.Day))

C#

DateTime date1 = Now.AddDays(-2000);
DateTime date2 = Now;
int diffYears = DateDiff(DateInterval.Year, date1, date2) - date1.DayOfYear > date2.DayOfYear ? 1 : 0;
int diffMonths = DateDiff(DateInterval.Month, date1, date2) - diffYears * 12 - date1.Day > date2.Day ? 1 : 0;
int diffDays = date2.Day >= date1.Day ? date2.Day - date1.Day : date2.Day + (System.DateTime.DaysInMonth(date1.Year, date1.Month) - date1.Day);

@Waleed A.K. 2015-10-22 18:04:13

you can use the following extension: Code

public static class Ext
{
    #region Public Methods

    public static int GetAge(this DateTime @this)
    {
        var today = DateTime.Today;
        return ((((today.Year - @this.Year) * 100) + (today.Month - @this.Month)) * 100 + today.Day - @this.Day) / 10000;
    }

    public static int DiffMonths(this DateTime @from, DateTime @to)
    {
        return (((((@to.Year - @from.Year) * 12) + (@to.Month - @from.Month)) * 100 + @to.Day - @from.Day) / 100);
    }

    public static int DiffYears(this DateTime @from, DateTime @to)
    {
        return ((((@to.Year - @from.Year) * 100) + (@to.Month - @from.Month)) * 100 + @to.Day - @from.Day) / 10000;
    }

    #endregion Public Methods
}

Implementation !

int Age;
int years;
int Months;
//Replace your own date
var d1 = new DateTime(2000, 10, 22);
var d2 = new DateTime(2003, 10, 20);
//Age
Age = d1.GetAge();
Age = d2.GetAge();
//positive
years = d1.DiffYears(d2);
Months = d1.DiffMonths(d2);
//negative
years = d2.DiffYears(d1);
Months = d2.DiffMonths(d1);
//Or
Months = Ext.DiffMonths(d1, d2);
years = Ext.DiffYears(d1, d2); 

@Edward Brey 2015-09-14 13:11:47

Use Noda Time:

LocalDate start = new LocalDate(2013, 1, 5);
LocalDate end = new LocalDate(2014, 6, 1);
Period period = Period.Between(start, end, PeriodUnits.Months);
Console.WriteLine(period.Months); // 16

(example source)

@Bhavesh Patel 2015-06-12 07:22:33

int nMonths = 0;
if (FDate.ToDateTime().Year == TDate.ToDateTime().Year)
     nMonths = TDate.ToDateTime().Month - FDate.ToDateTime().Month;                         
else
nMonths = (12 - FDate.Month) + TDate.Month;                          

@Konstantin Chernov 2015-01-21 11:57:45

Here's how we approach this:

public static int MonthDiff(DateTime date1, DateTime date2)
{
    if (date1.Month < date2.Month)
    {
        return (date2.Year - date1.Year) * 12 + date2.Month - date1.Month;
    }
    else
    {
        return (date2.Year - date1.Year - 1) * 12 + date2.Month - date1.Month + 12;
    }
}

@Chirag 2014-04-05 07:01:54

To get difference in months (both start and end inclusive), irrespective of dates:

DateTime start = new DateTime(2013, 1, 1);
DateTime end = new DateTime(2014, 2, 1);
var diffMonths = (end.Month + end.Year * 12) - (start.Month + start.Year * 12);

@paul 2014-12-18 06:35:36

Imagine start and end are identical. Then you get a result of 1. How is that right? Why do you add 1 to the result? Who is up-voting this answer :-/ ?

@Chirag 2014-12-18 11:29:26

For identical dates, it will give output as 1. Basically, it will count all the months inclusive start and end months.

@paul 2014-12-18 11:57:43

doesn't sound like the difference between two items to me. What is the difference between 2 and 2? Is it really 1? I would suggest the difference is 0.

@user687474 2014-04-05 08:09:29

You can use the DateDiff class of the Time Period Library for .NET:

// ----------------------------------------------------------------------
public void DateDiffSample()
{
  DateTime date1 = new DateTime( 2009, 11, 8, 7, 13, 59 );
  DateTime date2 = new DateTime( 2011, 3, 20, 19, 55, 28 );
  DateDiff dateDiff = new DateDiff( date1, date2 );

  // differences
  Console.WriteLine( "DateDiff.Months: {0}", dateDiff.Months );
  // > DateDiff.Months: 16

  // elapsed
  Console.WriteLine( "DateDiff.ElapsedMonths: {0}", dateDiff.ElapsedMonths );
  // > DateDiff.ElapsedMonths: 4

  // description
  Console.WriteLine( "DateDiff.GetDescription(6): {0}", dateDiff.GetDescription( 6 ) );
  // > DateDiff.GetDescription(6): 1 Year 4 Months 12 Days 12 Hours 41 Mins 29 Secs
} // DateDiffSample

@Paul 2014-01-23 17:22:03

  var dt1 = (DateTime.Now.Year * 12) + DateTime.Now.Month;
  var dt2 = (DateTime.Now.AddMonths(-13).Year * 12) + DateTime.Now.AddMonths(-13).Month;
  Console.WriteLine(dt1);
  Console.WriteLine(dt2);
  Console.WriteLine((dt1 - dt2));

Related Questions

Sponsored Content

40 Answered Questions

[SOLVED] Detecting an "invalid date" Date instance in JavaScript

  • 2009-08-30 11:34:40
  • orip
  • 680074 View
  • 1284 Score
  • 40 Answer
  • Tags:   javascript date

61 Answered Questions

[SOLVED] What is the difference between String and string in C#?

32 Answered Questions

[SOLVED] What is the difference between const and readonly?

49 Answered Questions

[SOLVED] How to format a JavaScript date

44 Answered Questions

[SOLVED] How do I get the current date in JavaScript?

  • 2009-10-07 11:39:02
  • Suresh Chaganti
  • 2303051 View
  • 1985 Score
  • 44 Answer
  • Tags:   javascript date

16 Answered Questions

[SOLVED] Difference between decimal, float and double in .NET?

9 Answered Questions

[SOLVED] Why is subtracting these two times (in 1927) giving a strange result?

  • 2011-07-27 08:15:58
  • Freewind
  • 602502 View
  • 6460 Score
  • 9 Answer
  • Tags:   java date timezone

35 Answered Questions

[SOLVED] Compare two dates with JavaScript

8 Answered Questions

[SOLVED] Number of days between two dates in Joda-Time

  • 2010-09-27 10:21:30
  • pvgoddijn
  • 185379 View
  • 314 Score
  • 8 Answer
  • Tags:   java date jodatime

15 Answered Questions

[SOLVED] Calculate difference between two dates (number of days)?

  • 2009-10-22 13:47:15
  • leora
  • 1015973 View
  • 958 Score
  • 15 Answer
  • Tags:   c# date

Sponsored Content