Displaying time in relative format
Many websites specially forum sites display time relative to the current time as “3 Hours 25 Minutes ago”, “30 Seconds ago” etc. In this post I will show a method using which we can convert datetime into descriptive relative time string.
The method takes 2 parameters 1. the time to process, 2. the time to which the output will be relative. Usually it is DateTime.UtcNow. There is also an overload which only takes the time to process where the second parameter defaults to DateTime.UtcNow. Let us see some sample output of this function.
Sample output
| Output | The date |
| 29 August 2007 | 8/29/2007 4:28:02 AM |
| 15 April (4 Months Ago) | 4/15/2008 4:28:02 AM |
| 16 August (12 Days Ago) | 8/16/2008 4:28:02 AM |
| 4 Hours 48 Minutes
Ago |
8/27/2008 11:40:02 PM |
| 43 Minutes 12 Seconds Ago | 8/28/2008 3:44:50 AM |
| 34
Seconds Ago |
8/28/2008 4:27:27 AM |
| 34 Seconds To go | 8/28/2008 4:28:37 AM |
| 43
Minutes 12 Seconds To go |
8/28/2008 5:11:14 AM |
| 4 Hours 48 Minutes To go | 8/28/2008 9:16:02
AM |
| 9 September (12 Days To go) | 9/9/2008 4:28:02 AM |
| 10 January 2009 (4 Months To
go) |
1/10/2009 4:28:02 AM |
| 28 August 2009 | 8/28/2009 4:28:02 AM |
Few points to note about this method
- If the date is older or newer than 12 months, it will output full date string. This is because I feel the relative time does not have much relevance beyond a certain threshold. You can always change the method to suit your needs.
- It does not display the year if the time is in the same year as the RelativeTo time.
- It will automatically add “ago” or “to go” at end of the output depending on whether the time is less than or greater than the relative to time.
- The method is implemented as a static method not as an extension method, so that it works in .net 2.0 as well. However, if you are using .net 3.5 then you can easily convert the code to an extension method for easier use.
The code follows
//The overload which takes only the time to process. The second parameter defaults to DateTime.UtcNow
public static string ToRelativeTimeString(DateTime time)
{
return ToRelativeTimeString(time, DateTime.UtcNow);
}//The overload which take both the parameters
public static string ToRelativeTimeString(DateTime time,DateTime RelativeTo)
{
TimeSpan ts = RelativeTo.Subtract(time).Duration();
string DateFormat=”d MMMM”;
string dir=(RelativeTo>time)?”Ago”:”To go”;
if(RelativeTo.Year!=time.Year)
DateFormat += ” yyyy”;
if(ts.Days <360)
{
//Months
if(ts.Days >=30)
return string.Format( “{0} ({1} Months {2})”, time.ToString(DateFormat), (int)(ts.Days /30),dir );
//Days
if(ts.Days >0)
return string.Format(”{0} ({1} Days {2})”, time.ToString(DateFormat), ts.Days ,dir );
//hours
if(ts.Hours>0)
return string.Format(”{0} Hours {1} Minutes {2}”, ts.Hours ,ts.Minutes , dir);
//minutes
if(ts.Minutes>0)
return string.Format(”{0} Minutes {1} Seconds {2}”, ts.Minutes ,ts.Seconds , dir);
//seconds
return string.Format(”{0} Seconds {1}”, ts.Seconds , dir);
}
return time.ToString(DateFormat);
}
Using the code
Using this method is very easy. Just call the ToRelativeTimeString() method passing it the DateTime to process.
Response.Write( ToRelativeTimeString( dt));
I also ran a quick and dirty performance test by calling this function with randomly generated dates 100000 times and results were surprising or at least was not what I expected. This function was equal in performance to DateTime.ToLongDateString() some times even beating it while processing dates lesser than a day. It was slightly expensive while processing dates older than a year as expected because after doing all the processing, it was using DateTime.ToString() with some custom date formatting to return the result. Still the extra overhead is really small (0.3 sec vs 0.35 sec for processing it 100000 times!).
Happy coding!
If you liked this post, please subscribe to this blog or kick this story on DotNetKicks.com .

August 28th, 2008 at 8:17 pm
Thank you for writing this! I have a project I’m working on right now where I was looking into doing just this sort of thing. You’ve saved me a lot of work!
August 28th, 2008 at 8:27 pm
Good to know that it helped you.
All the best for the project,
Nirandas
August 28th, 2008 at 9:19 pm
Nice! let’s try to translate it using the CurrentCulture setting
September 4th, 2008 at 1:28 am
Perfect timing! Thanks for the handy snippet!
September 7th, 2008 at 3:43 am
I believe that you have to use Total*** or else you will get the wrong output.
if(ts.TotalDays < 360) and so on..
September 7th, 2008 at 9:06 am
@Anders
In this case there is no need to use Total** methods as the timespan has already been converted to a positive timespan by calling the duration() method.
TimeSpan ts = RelativeTo.Subtract(time).Duration();
Hence in this case, the TotalDays and days would return the difference between the 2 dates as a positive value.
Nirandas