104

How can I calculate date difference between two dates in years?

For example: (Datetime.Now.Today() - 11/03/2007) in years.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
msbyuva
  • 3,467
  • 13
  • 63
  • 87
  • 1
    The code you've marked as the answer is actual fact incorrect. It can return incorrect results – Mick Jun 29 '15 at 07:47

18 Answers18

145

I have written an implementation that properly works with dates exactly one year apart.

However, it does not gracefully handle negative timespans, unlike the other algorithm. It also doesn't use its own date arithmetic, instead relying upon the standard library for that.

So without further ado, here is the code:

DateTime zeroTime = new DateTime(1, 1, 1);

DateTime a = new DateTime(2007, 1, 1);
DateTime b = new DateTime(2008, 1, 1);

TimeSpan span = b - a;
// Because we start at year 1 for the Gregorian
// calendar, we must subtract a year here.
int years = (zeroTime + span).Year - 1;

// 1, where my other algorithm resulted in 0.
Console.WriteLine("Yrs elapsed: " + years);
Grigory Zhadko
  • 1,484
  • 1
  • 19
  • 33
Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
  • 9
    That handles leap years on average, but it will be off by one for up to 18 hours out of each year. – Ben Voigt Nov 08 '10 at 19:48
  • 7
    Using this method, the difference between 1/1/2007 and 1/1/2008 would be 0 years. Intuitively, it should be 1 year. – o. nate Nov 08 '10 at 21:16
  • 4
    Good point. I do not know any other effective way of doing this though... possibly add one to the day? – Richard J. Ross III Nov 08 '10 at 23:09
  • @benvoigt I realize its been forever since you left that comment - i just wanted you to know that I believe that that bug has been fixed with this update that I have just made. – Richard J. Ross III Feb 09 '13 at 06:17
  • @o.nate after searching though the docs for a solution to that problem this evening, I do believe that I have solved that problem. Thank you for pointing it out, it saved me a major headache in my latest project! – Richard J. Ross III Feb 09 '13 at 06:17
  • 6
    This broke for us today (12/31). The addition math causes an off-by-one-day problem for when the 12/31 date is compared against 1/1. We fixed it by first subtracting one day from the span. – dotjosh Dec 31 '14 at 19:03
  • 4
    The probability this will give you the correct answer is quite high, However, if you want this to work 100% of the time, this answer is wrong. Because of leap years. the start date matters! – Mick Jun 29 '15 at 03:21
67

Use:

int Years(DateTime start, DateTime end)
{
    return (end.Year - start.Year - 1) +
        (((end.Month > start.Month) ||
        ((end.Month == start.Month) && (end.Day >= start.Day))) ? 1 : 0);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dana
  • 17,267
  • 6
  • 64
  • 88
  • 2
    This would say that 2008-Nov-02 is one year after 2007-Nov-03, most people would say it's one day short. – Ben Voigt Nov 08 '10 at 20:00
  • You are right. I've updated my code to go strictly off the Year, Month and Day properties. It gets a little uglier now but works for leap years. – dana Nov 08 '10 at 20:13
  • 1
    I know it's an old answer, but just wanted to add that this can be simplified by comparing DayOfYear property instead of comparing both Month and Year together. – Tarec Jun 28 '18 at 12:06
  • 1
    @Tarec - my first revision used the `DayOfYear` property... But I changed things due to @BenVoigt's comment. – dana Jun 29 '18 at 01:04
28

We had to code a check to establish if the difference between two dates, a start and end date was greater than 2 years.

Thanks to the tips above it was done as follows:

 DateTime StartDate = Convert.ToDateTime("01/01/2012");
 DateTime EndDate = Convert.ToDateTime("01/01/2014");
 DateTime TwoYears = StartDate.AddYears(2);

 if EndDate > TwoYears .....
Ruchir
  • 289
  • 3
  • 2
  • 8
    Shorter version: If ( Birthday.AddYears(18) > DateTime.UtcNow.Date ) //under 18 – Code Slinger Feb 16 '16 at 20:33
  • Instead of doing DateTime TwoYears = StartDate.AddYears(2); if you minus 1 day from that : DateTime TwoYears = StartDate.AddYears(2).AddDays(-1); you will get more accurate answer... I don't know it depends on requirement. – Renascent May 29 '18 at 06:53
21

If you need it for knowing someone's age for trivial reasons then Timespan is OK but if you need for calculating superannuation, long term deposits or anything else for financial, scientific or legal purposes then I'm afraid Timespan won't be accurate enough because Timespan assumes that every year has the same number of days, same # of hours and same # of seconds).

In reality the length of some years will vary (for different reasons that are outside the scope of this answer). To get around Timespan's limitation then you can mimic what Excel does which is:

    public int GetDifferenceInYears(DateTime startDate, DateTime endDate)
    {
        //Excel documentation says "COMPLETE calendar years in between dates"
        int years = endDate.Year - startDate.Year;

        if (startDate.Month == endDate.Month &&// if the start month and the end month are the same
            endDate.Day < startDate.Day// AND the end day is less than the start day
            || endDate.Month < startDate.Month)// OR if the end month is less than the start month
        {
            years--;
        }

        return years;
    }
davomcdavo
  • 579
  • 4
  • 9
  • 1
    I've been using this old code forever, but I just got bitten by a leap year. Client reported a 3 year difference was being displayed as two years - turns out that 29th Feb -> 28th Feb is rounded down and loses a year from what a human would actually expect. – Whelkaholism Aug 17 '21 at 10:58
13
var totalYears = 
    (DateTime.Today - new DateTime(2007, 03, 11)).TotalDays
    / 365.2425;

Average days from Wikipedia/Leap_year.

Albin Sunnanbo
  • 46,430
  • 8
  • 69
  • 108
  • 8
    On average correct. But not always. – Mick Jun 29 '15 at 07:51
  • @Mick Could you please explain in what specific case it would become wrong ? Thanks. – Nam Le Jun 09 '21 at 11:21
  • 3
    @NamLe the number of days in a year is either 365 days or 366 days if it is a leap year. It is never 365.2425 days. Therefore this formula is only going to be approximately correct. – Mick Jun 10 '21 at 05:56
  • That's not quite true. This "approximation" is actually an exact number of days in a year (that's why we're having leap years - to compensate this quarter of a day) and with a proper rounding, you'll always get a correct number of years. – montonero Jul 02 '21 at 22:06
10
int Age = new DateTime((DateTime.Now - BirthDateTime).Ticks).Year;

To calculate the elapsed years (age), the result will be minus one.

var timeSpan = DateTime.Now - birthDateTime;
int age = new DateTime(timeSpan.Ticks).Year - 1;
Fabio
  • 3,020
  • 4
  • 39
  • 62
Predders
  • 375
  • 3
  • 12
6

Here is a neat trick which lets the system deal with leap years automagically. It gives an accurate answer for all date combinations.

DateTime dt1 = new DateTime(1987, 9, 23, 13, 12, 12, 0);
DateTime dt2 = new DateTime(2007, 6, 15, 16, 25, 46, 0);

DateTime tmp = dt1;
int years = -1;
while (tmp < dt2)
{
    years++;
    tmp = tmp.AddYears(1);
}

Console.WriteLine("{0}", years);
Martin
  • 91
  • 2
  • 7
  • It's a nice idea, but instead of changing tmp date in a loop, you should increment the number of years instead. That will work properly if you expect 4 to be returned for Feb 29 2012 - Feb 29 2016. – altso Jan 07 '19 at 19:18
5

It's unclear how you want to handle fractional years, but perhaps like this:

DateTime now = DateTime.Now;
DateTime origin = new DateTime(2007, 11, 3);
int calendar_years = now.Year - origin.Year;
int whole_years = calendar_years - ((now.AddYears(-calendar_years) >= origin)? 0: 1);
int another_method = calendar_years - ((now.Month - origin.Month) * 32 >= origin.Day - now.Day)? 0: 1);
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • According to this method, 2/28/2009 is 1 year after 2/29/2008, whereas it seems like it should be slightly less than 1 year. I guess the handling of leap years is always going to be slightly unsatisfying. – o. nate Nov 08 '10 at 21:44
  • @o. nate: Fixed, maybe (using a trick found on that other question spotted by Doggett). I think something like Dana's solution may be necessary to fix the leap day case in both directions. – Ben Voigt Nov 08 '10 at 21:59
3

I implemented an extension method to get the number of years between two dates, rounded by whole months.

    /// <summary>
    /// Gets the total number of years between two dates, rounded to whole months.
    /// Examples: 
    /// 2011-12-14, 2012-12-15 returns 1.
    /// 2011-12-14, 2012-12-14 returns 1.
    /// 2011-12-14, 2012-12-13 returns 0,9167.
    /// </summary>
    /// <param name="start">
    /// Stardate of time period
    /// </param>
    /// <param name="end">
    /// Enddate of time period
    /// </param>
    /// <returns>
    /// Total Years between the two days
    /// </returns>
    public static double DifferenceTotalYears(this DateTime start, DateTime end)
    {
        // Get difference in total months.
        int months = ((end.Year - start.Year) * 12) + (end.Month - start.Month);

        // substract 1 month if end month is not completed
        if (end.Day < start.Day)
        {
            months--;
        }

        double totalyears = months / 12d;
        return totalyears;
    }
Felix
  • 97
  • 4
2

I found this at TimeSpan for years, months and days:

DateTime target_dob = THE_DOB;
DateTime true_age = DateTime.MinValue + ((TimeSpan)(DateTime.Now - target_dob )); // Minimum value as 1/1/1
int yr = true_age.Year - 1;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
bizl
  • 1,535
  • 2
  • 12
  • 21
  • Doesn't work for leap years... Try "5-Oct-2024" from "6-Oct-1973". It reports my age as 51, but I'll only be 50. – NobleGuy May 11 '23 at 11:26
2
    public string GetAgeText(DateTime birthDate)
    {
        const double ApproxDaysPerMonth = 30.4375;
        const double ApproxDaysPerYear = 365.25;

        int iDays = (DateTime.Now - birthDate).Days;

        int iYear = (int)(iDays / ApproxDaysPerYear);
        iDays -= (int)(iYear * ApproxDaysPerYear);

        int iMonths = (int)(iDays / ApproxDaysPerMonth);
        iDays -= (int)(iMonths * ApproxDaysPerMonth);

        return string.Format("{0} år, {1} måneder, {2} dage", iYear, iMonths, iDays);
    }
Jens Borrisholt
  • 101
  • 1
  • 2
0
DateTime musteriDogum = new DateTime(dogumYil, dogumAy, dogumGun);

int additionalDays = ((DateTime.Now.Year - dogumYil) / 4); //Count of the years with 366 days

int extraDays = additionalDays + ((DateTime.Now.Year % 4 == 0 || musteriDogum.Year % 4 == 0) ? 1 : 0); //We add 1 if this year or year inserted has 366 days

int yearsOld = ((DateTime.Now - musteriDogum).Days - extraDays ) / 365; // Now we extract these extra days from total days and we can divide to 365
Tim
  • 41,901
  • 18
  • 127
  • 145
0

Simple solution:

public int getYearDiff(DateTime startDate, DateTime endDate){
    int y = Year(endDate) - Year(startDate);
    int startMonth = Month(startDate);
    int endMonth = Month(endDate);
    if (endMonth < startMonth) 
        return y - 1;
    if (endMonth > startMonth) 
        return y;
    return (Day(endDate) < Day(startDate) ? y - 1 : y);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vedran
  • 21
  • 3
0

This is the best code to calculate year and month difference:

DateTime firstDate = DateTime.Parse("1/31/2019");
DateTime secondDate = DateTime.Parse("2/1/2016");

int totalYears = firstDate.Year - secondDate.Year;
int totalMonths = 0;

if (firstDate.Month > secondDate.Month)
    totalMonths = firstDate.Month - secondDate.Month;
else if (firstDate.Month < secondDate.Month)
{
    totalYears -= 1;
    int monthDifference = secondDate.Month - firstDate.Month;
    totalMonths = 12 - monthDifference;
}

if ((firstDate.Day - secondDate.Day) == 30)
{
    totalMonths += 1;
    if (totalMonths % 12 == 0)
    {
        totalYears += 1;
        totalMonths = 0;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Numan Ali
  • 223
  • 2
  • 13
0

Works perfect:

    internal static int GetDifferenceInYears(DateTime startDate)
    {
        int finalResult = 0;

        const int DaysInYear = 365;

        DateTime endDate = DateTime.Now;

        TimeSpan timeSpan = endDate - startDate;

        if (timeSpan.TotalDays > 365)
        {
            finalResult = (int)Math.Round((timeSpan.TotalDays / DaysInYear), MidpointRounding.ToEven);
        }

        return finalResult;
    }
ketan
  • 19,129
  • 42
  • 60
  • 98
darkwood
  • 55
  • 8
0

If you're dealing with months and years you need something that knows how many days each month has and which years are leap years.

Enter the Gregorian Calendar (and other culture-specific Calendar implementations).

While Calendar doesn't provide methods to directly calculate the difference between two points in time, it does have methods such as

DateTime AddWeeks(DateTime time, int weeks)
DateTime AddMonths(DateTime time, int months)
DateTime AddYears(DateTime time, int years)
mattk
  • 1,335
  • 1
  • 14
  • 19
-1

Maybe this will be helpful for answering the question: Count of days in given year,

new DateTime(anyDate.Year, 12, 31).DayOfYear //will include leap years too

Regarding DateTime.DayOfYear Property.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nigrimmist
  • 10,289
  • 4
  • 52
  • 53
-1

The following is based off Dana's simple code which produces the correct answer in most cases. But it did not take in to account less than a year between dates. So here is the code that I use to produce consistent results:

public static int DateDiffYears(DateTime startDate, DateTime endDate)
{
    var yr = endDate.Year - startDate.Year - 1 +
             (endDate.Month >= startDate.Month && endDate.Day >= startDate.Day ? 1 : 0);
    return yr < 0 ? 0 : yr;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • This also exhibits the leap year behaviour of @davomcdavo's answer – Whelkaholism Aug 17 '21 at 10:59
  • You can't replace `(end.Month > start.Month) || ((end.Month == start.Month) && (end.Day >= start.Day))` with `endDate.Month >= startDate.Month && endDate.Day >= startDate.Day` – Jon Hallin Aug 30 '21 at 07:54