Find elapsed time in years, months, days, hours, minutes, and seconds in C#

[elapsed time]

The TimeSpan structure represents an elapsed time. It has Days, Hours, Minutes, Seconds, and Milliseconds properties that tell you about the time that has passed. For example, if two dates are 3 days and 4 hours apart, then Days = 3 and Hours = 4.

It’s not so easy to tell how far apart two dates are in years and months, however, because years and months don’t all have the same length. Rather than producing some results, Microsoft simply didn’t include Years and and Months properties in the TimeSpan structure.

This example calculates a time difference with years and months, but it sometimes produces surprising results. For example, the difference between Feb 29, 2004 and Feb 28, 2008 is 3 years, 11 months, and 31 days. For another example, the difference between Feb 29, 2004 and Feb 28, 2007 is 3 years because there is no Feb 29, 2007.

The following GetElapsedTime method returns the elapsed time between two dates in years, months, days, hours, minutes, seconds, and milliseconds.

// Return the number of years, months, days, hours,
// minutes, seconds, and milliseconds you need to add to
// from_date to get to_date.
private void GetElapsedTime(DateTime from_date, DateTime to_date, 
    out int years, out int months, out int days, out int hours,
    out int minutes, out int seconds, out int milliseconds)
{
    // If from_date > to_date, switch them around.
    if (from_date > to_date)
    {
        GetElapsedTime(to_date, from_date,
            out years, out months, out days, out hours,
            out minutes, out seconds, out milliseconds);
        years = -years;
        months = -months;
        days = -days;
        hours = -hours;
        minutes = -minutes;
        seconds = -seconds;
        milliseconds = -milliseconds;
    }
    else
    {
        // Handle the years.
        years = to_date.Year - from_date.Year;

        // See if we went too far.
        DateTime test_date = from_date.AddMonths(12 * years);
        if (test_date > to_date)
        {
            years--;
            test_date = from_date.AddMonths(12 * years);
        }

        // Add months until we go too far.
        months = 0;
        while (test_date <= to_date)
        {
            months++;
            test_date = from_date.AddMonths(12 * years + months);
        }
        months--;

        // Subtract to see how many more days,
        // hours, minutes, etc. we need.
        from_date = from_date.AddMonths(12 * years + months);
        TimeSpan remainder = to_date - from_date;
        days = remainder.Days;
        hours = remainder.Hours;
        minutes = remainder.Minutes;
        seconds = remainder.Seconds;
        milliseconds = remainder.Milliseconds;
    }
}

If the start date is after the end date, then the method calls itself reversing its dates and negating the results.

After ensuring that the start date comes before the end date, the program subtracts the dates’ years and adds that number to the start date. If the result is after the end date, it subtracts 1 from the number of years.

Next the program adds months to the start date until the result is after the end date. It then subtracts the last month.

The program works in months so the DateTime structure’s AddMonths method can handle such oddities as months with different numbers of days. For example, if you add 1 month to March 31, you get April 30 because April only has 30 days.

After it has found the largest number of years and months it can add to the start date, the program uses a TimeSpan to represent the time between the adjusted start date and the end date. It then uses the TimeSpan structure’s Days, Hours, Minutes, Seconds, and Milliseconds properties.

Yes this is confusing. There was a reason Microsoft didn’t add this to the TimeSpan structure!


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in parsing, variables and tagged , , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *