A Real Timespan Object With .Years & .Months

Erx_VB.NExT.Coder picture Erx_VB.NExT.Coder · Dec 16, 2009 · Viewed 37.7k times · Source

Consider the following 2 scenarios: Scenario 1). Today is May 1st 2012, and Scenario 2). Today is September 1st 2012.

Now, consider that we write on our webpage the following about a comment someone has left: "This comment was written 3 months and 12 days ago". The amount of days in both these scenarios will ALWAYS be different even though the statement is exactly the same. In Scenario 1, "3 months and 12 days" would equal 102 days. However, in Scenario 2, "3 months and 12 days" would be 104 days!

Now, to corner in on my point, lets use a different example and say that someone left a comment on our site on Jan 30th 2013, and today is March 10th 2013. Our real TimeSpan object needs to know this relative date, and can figure out the following:

  • That there is 10 days in March,
  • That there is 1 day in Jan (counting from 30th to 31st).
  • That the month Feb is one month regardless of how many days there are in it (even though it's 28 days).

So, it would mean 10 days + 1 day + 1 month total, translating to This comment was posted 1 Month and 11 Days ago.

Now, if you used the MS style TimeSpan object (or any TimeSpan object in any language), it would give you the number of days from 30th Jan to 10 March (39 days), and because the TimeSpan object doesn't store relative date (the base/initial date we subtracted to get the TimeSpan), if you asked it how many months and days it has been, it will assume there is 30 days in one month, or even worst, the average which is greater than 30 days, and return the rest in days, so to get to 39 days, it will tell you it's been 1 Month and 9 Days and you will get the This comment was posted 1 Month and 9 Days ago message. Remember, both these scenarios have the same start date and same current/end date, yes the Microsoft TimeSpan object, by not allowing us to tell it the month of Feb 2013 should be considered, has given us a completely different TimeSpan, off by a whole 2 days. It has, in effect, lied to us.

The problem is, people will believe this, and who knows what perceptions they may have, how their perceptions of the past may change and the decisions & life choices they may make when trying to reconstruct events within the past inside their own minds, while never noticing or understanding the drawback and inherent failure of representing time that is so pervasive everywhere today. They will not understand that programming languages don't realize (or care) that last month had 31 days in it, as oppposed to 30, 29 or 28 - or visa versa, and that this adds up when you increase the TimeSpan.

This is the problem at the heart of this post. I understand that most people will not care about this difference (but be sure that some of us do, and cannot have this on our backs), and if this doesn't bother you, thats ok. I wish it didn't bother me, I would have saved myself some time, stress and disappointment. If this is not a bother, you can use the function for the efficient textual display of relative time (customizable to 1 to 6 nodes from seconds to years), instead of using it for the usually negligible accuracy it provides.

To my disappointment I noticed that there is no real timespan object, if you get a timespan, and do a .years or .months you'll get nothing, you'll only get .days and lower because a timeSpan object doesn't carry anything to tell it which month or year the timeSpan was created on. Therefore it'll never really know how many months it's been since days in each month vary over a year and even further over a leap year.

In response to this, I'll post a function I developed in order to get ACCURATE readings and be able to return things like the following on my ASP.NET web page...

Posted 4 years, 3 months, 14 days, 15 hours, 18 minutes and 24 seconds ago

I figured there'd be a …

timeSpan.GetActualNumberOf[Months/Days/Hours/etc] (base date must be provided of course)

… type method on this datatype, but there wasn't.

All you'd really have to do is create another property on the timeSpan object to give it a base date on which the difference was calculated, then the above lovely string would be calculable pretty easily, and a .year & .month would exist!

UPDATE: I have significantly expanded upon and updated my official answer and code usage details in my answer below, 100% working answer and code (in full), accurate and exact relative time/dates, no approximations - thanks.

Answer

brianary picture brianary · Dec 18, 2009

Here's how to add some extension methods for this with C# using mean values:

public static class TimeSpanExtensions
{
    public static int GetYears(this TimeSpan timespan)
    {
        return (int)(timespan.Days/365.2425);
    }
    public static int GetMonths(this TimeSpan timespan)
    {
        return (int)(timespan.Days/30.436875);
    }
}