Jon H
Jon H

Reputation: 1071

Subtracting 2 dates

I need to be able to subtract 2 dates and get back the years and months between the 2.

Does anyone know of any easy ways to do this?

I have looked at the TimeSpan returned when subtracting dates but there is no 'NumberOfYears' etc option!

EDIT:

I have found the following article

http://www.codeproject.com/KB/datetime/TimePeriod.aspx?msg=4078849#xx4078849xx

it is awesome!

Upvotes: 0

Views: 415

Answers (5)

Lloyd Powell
Lloyd Powell

Reputation: 18810

You could take off the ticks since the start of time (well not the start of time, but 01/01/0001) :

// Assuming date 1 is the later date
DateTime newDate = new DateTime(myDate1.Ticks - myDate2.Ticks);

// NOTE : you might need to take 1 off each property, as they start at 1
string.Format("{0} Years, {1} Months, {2} Days", newDate.Year, newDate.Month, newDate.Day);

or

You could create a module that will do your workings for you that will loop counting the number of years between the dates until either the years are equal or the year is one less in the case that the earlier month is greater. Then you can loop until the months are equal without forgetting to drop from 12 to 1.

int yearCount = 0;
int monthCount = 0;
int earliestYear = 0;
int earliestMonth = 0;
int latestYear = 0;
int latestMonth = 0;

// Get the earlier date, assuming that you haven't calculated which date is the latter already.
if (myDate1 > myDate2)
{
   earliestYear = myDate2.Year;
   earliestMonth = myDate2.Month;
}
else
{
   latestYear = myDate1.Year;
   latestMonth = myDate1.Month;
}

// Get the years between (remember not to include a year where the earlier dates month is greater than the latter. E.g. 09/2011 -> 01/2013 will only be 1 year, not 2!
while(earliestYear < latestYear && (earliestMonth <= latestMonth || earliestYear < (latestYear - 1)))
{
   yearCount++;
   earliestYear++;
}

// Finally get the months between, moving back to january after december.
while (earliestMonth != latestMonth)
{
   monthCount++;

   if (earliestMonth == 12)
   {
      earliestMonth = 1;
   }
   else
   {
      earliestMonth++;
   }
}

string.Format("{0} years and {1} months", yearCount, monthCount);

This is untested code written on the fly to give you a rough idea.

This also assumes that you would represent there being 1 month between two dates such as 29/02/1988 and 01/03/1988 (British Date Time Format)

or 

You could try using a timespan to complete the task, there is no way to get the years without a bit of manual code although I'm sure you can figure that part out :-) (e.g. something like days / 365.25)

TimeSpan timebetween = myDate1 - myDate2;

Upvotes: 3

zeFrenchy
zeFrenchy

Reputation: 6591

You can create a DateTime with the diff in ticks.

DateTime tmp = new DateTime(date1.Ticks - date2.Ticks);
Console.WriteLine(tmp.Year - 1);
Console.WriteLine(tmp.Month - 1);
Console.WriteLine(tmp.Day - 1);

You have to subtract 1 from everything since 1/1/1 is first possible date, not 0/0/0

Upvotes: 0

Jon H
Jon H

Reputation: 1071

The best solution I have found is this code projects article:

http://www.codeproject.com/KB/datetime/TimePeriod.aspx?msg=4078849#xx4078849xx

Upvotes: 0

Johannes Kommer
Johannes Kommer

Reputation: 6451

Why not create an extension method on DateTime which returns a Tuple<int, int> or a custom class to serve your needs? Especially as TimeSpan will not serve your need nicely, as you'd have to calculate from days to months and years (and take the length of every month into account.)

public static Tuple<int, int> GetYearsAndMonthsDifference(this DateTime dt1, DateTime dt2)
{
    DateTime laterDate;
    DateTime earlierDate;

    if (dt1 > dt2)
    {
        earlierDate = dt2;
        laterDate = dt1;
    }
    else
    {
        earlierDate = dt1;
        laterDate = dt2;
    }

    int months = 0;

    while(earlierDate.Month != laterDate.Month || earlierDate.Year != laterDate.Year)
    {
        months++;
        earlierDate = earlierDate.AddMonths(1);
    }

    return Tuple.Create<int, int>(months / 12, months % 12);
}

Usage:

var dt1 = DateTime.Now;
var dt2 = new DateTime(2010, 1, 1);

var difference = dt1.GetYearsAndMonthsDifference(dt2);

Console.WriteLine(string.Format("Years: {0}", difference.Item1));
Console.WriteLine(string.Format("Months: {0}", difference.Item2));

N.B: If you do not like Item1, Item2 then you could always create a custom structure / class with better and return this, instead of a Tuple<int, int>.

Upvotes: 0

Related Questions