C# and Javascript port of Bill's answer
Works for me - adding it to both Soapi libraries. See the JS version in action here
One thing to keep in mind is that dates coming from the API are UTC. In order to get a viable diff, you need to convert your Now
to UTC.
c#
/// <summary>
/// Formats the time elapsed between fromDate and now.
/// See http://stackoverflow.com/questions/11/how-do-i-calculate-relative-time/
/// and http://stackapps.com/questions/1009/how-to-format-time-since-xxx-e-g-4-minutes-ago-similar-to-stack-exchange-site/1034#1034
/// </summary>
/// <param name="fromDate">the start time</param>
/// <returns>the formatted time elapsed.</returns>
/// <remarks>A direct port of Bill the Lizards answer</remarks>
public static string FormatElapsedTime(DateTime fromDate)
{
const int second = 1;
const int minute = 60 * second;
const int hour = 60 * minute;
const int day = 24 * hour;
const int month = 30 * day;
int delta = (int) (DateTime.Now.ToUniversalTime() - fromDate).TotalSeconds;
if (delta < 1 * minute)
{
return delta == 1 ? "one second ago" : delta + " seconds ago";
}
if (delta < 2 * minute)
{
return "a minute ago";
}
if (delta < 45 * minute)
{
return (delta / minute) + " minutes ago";
}
if (delta < 90 * minute)
{
return "an hour ago";
}
if (delta < 24 * hour)
{
return (delta / hour) + " hours ago";
}
if (delta < 48 * hour)
{
return "yesterday";
}
if (delta < 30 * day)
{
return (delta / day) + " days ago";
}
if (delta < 12 * month)
{
int months = (int) (Math.Floor(((delta / day) / 30)));
return months <= 1 ? "one month ago" : months + " months ago";
}
int years = (int)(Math.Floor((delta / day) / 365));
return years <= 1 ? "one year ago" : years + " years ago";
}
}
JavaScript
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>
<script type="text/javascript">
function formatElapsedTime(fromDate)
{
var second = 1;
var minute = 60 * second;
var hour = 60 * minute;
var day = 24 * hour;
var month = 30 * day;
var delta = (new Date() - fromDate) / 1000;
if (delta < 1 * minute)
{
return delta == 1 ? "one second ago" : Math.floor(delta) + " seconds ago";
}
if (delta < 2 * minute)
{
return "a minute ago";
}
if (delta < 45 * minute)
{
return Math.floor(delta / minute) + " minutes ago";
}
if (delta < 90 * minute)
{
return "an hour ago";
}
if (delta < 24 * hour)
{
return Math.floor(delta / hour) + " hours ago";
}
if (delta < 48 * hour)
{
return "yesterday";
}
if (delta < 30 * day)
{
return Math.floor(delta / day) + " days ago";
}
if (delta < 12 * month)
{
var months = Math.floor((delta / day) / 30);
return months <= 1 ? "one month ago" : months + " months ago";
}
var years = Math.floor((delta / day) / 365);
return years <= 1 ? "one year ago" : years + " years ago";
}
function tests()
{
function assertEquals(expected, actual)
{
var equals = expected == actual;
var output = document.getElementById("output");
var div = document.createElement("div");
div.innerHTML = (equals ? "passed" : "FAILED") + " : expected " + expected + " and got " + actual;
output.appendChild(div)
}
var now = (new Date()).getTime();
assertEquals("one second ago", formatElapsedTime(now - 1000));
assertEquals("2 seconds ago", formatElapsedTime(now - 2000));
assertEquals("30 seconds ago", formatElapsedTime(now - 30000));
assertEquals("59 seconds ago", formatElapsedTime(now - 59000));
assertEquals("a minute ago", formatElapsedTime(now - 60000));
assertEquals("a minute ago", formatElapsedTime(now - 61000));
assertEquals("a minute ago", formatElapsedTime(now - 119000));
assertEquals("2 minutes ago", formatElapsedTime(now - 120000));
assertEquals("2 minutes ago", formatElapsedTime(now - 121000));
assertEquals("2 minutes ago", formatElapsedTime(now - 179000));
assertEquals("3 minutes ago", formatElapsedTime(now - 180000));
assertEquals("44 minutes ago", formatElapsedTime(now - (44 * 60000)));
assertEquals("an hour ago", formatElapsedTime(now - (45 * 60000)));
assertEquals("an hour ago", formatElapsedTime(now - (89 * 60000)));
assertEquals("1 hours ago", formatElapsedTime(now - (90 * 60000)));
assertEquals("1 hours ago", formatElapsedTime(now - (119 * 60000)));
assertEquals("2 hours ago", formatElapsedTime(now - (120 * 60000)));
assertEquals("2 hours ago", formatElapsedTime(now - (179 * 60000)));
assertEquals("3 hours ago", formatElapsedTime(now - (180 * 60000)));
assertEquals("23 hours ago", formatElapsedTime(now - (23 * 60 * 60000)));
assertEquals("yesterday", formatElapsedTime(now - (24 * 60 * 60000)));
assertEquals("yesterday", formatElapsedTime(now - (47 * 60 * 60000)));
assertEquals("2 days ago", formatElapsedTime(now - (48 * 60 * 60000)));
assertEquals("3 days ago", formatElapsedTime(now - (3 * 24 * 60 * 60000)));
assertEquals("14 days ago", formatElapsedTime(now - (14 * 24 * 60 * 60000)));
assertEquals("29 days ago", formatElapsedTime(now - (29 * 24 * 60 * 60000)));
assertEquals("one month ago", formatElapsedTime(now - (30 * 24 * 60 * 60000)));
assertEquals("one month ago", formatElapsedTime(now - (59 * 24 * 60 * 60000)));
assertEquals("2 months ago", formatElapsedTime(now - (60 * 24 * 60 * 60000)));
assertEquals("2 months ago", formatElapsedTime(now - (89 * 24 * 60 * 60000)));
assertEquals("3 months ago", formatElapsedTime(now - (3 * 30 * 24 * 60 * 60000)));
assertEquals("11 months ago", formatElapsedTime(now - (11 * 30 * 24 * 60 * 60000)));
assertEquals("one year ago", formatElapsedTime(now - (12 * 30 * 24 * 60 * 60000)));
assertEquals("one year ago", formatElapsedTime(now - (18 * 30 * 24 * 60 * 60000)));
assertEquals("one year ago", formatElapsedTime(now - (23 * 30 * 24 * 60 * 60000)));
// a little bit of error in the calculation shows up here.
assertEquals("one year ago", formatElapsedTime(now - (24 * 30 * 24 * 60 * 60000)));
assertEquals("2 years ago", formatElapsedTime(now - (25 * 30 * 24 * 60 * 60000)));
}
</script>
</head>
<body onload="tests()">
<div id="output">
</div>
</body>
</html>
Test Results
passed : expected one second ago and got one second ago
passed : expected 2 seconds ago and got 2 seconds ago
passed : expected 30 seconds ago and got 30 seconds ago
passed : expected 59 seconds ago and got 59 seconds ago
passed : expected a minute ago and got a minute ago
passed : expected a minute ago and got a minute ago
passed : expected a minute ago and got a minute ago
passed : expected 2 minutes ago and got 2 minutes ago
passed : expected 2 minutes ago and got 2 minutes ago
passed : expected 2 minutes ago and got 2 minutes ago
passed : expected 3 minutes ago and got 3 minutes ago
passed : expected 44 minutes ago and got 44 minutes ago
passed : expected an hour ago and got an hour ago
passed : expected an hour ago and got an hour ago
passed : expected 1 hours ago and got 1 hours ago
passed : expected 1 hours ago and got 1 hours ago
passed : expected 2 hours ago and got 2 hours ago
passed : expected 2 hours ago and got 2 hours ago
passed : expected 3 hours ago and got 3 hours ago
passed : expected 23 hours ago and got 23 hours ago
passed : expected yesterday and got yesterday
passed : expected yesterday and got yesterday
passed : expected 2 days ago and got 2 days ago
passed : expected 3 days ago and got 3 days ago
passed : expected 14 days ago and got 14 days ago
passed : expected 29 days ago and got 29 days ago
passed : expected one month ago and got one month ago
passed : expected one month ago and got one month ago
passed : expected 2 months ago and got 2 months ago
passed : expected 2 months ago and got 2 months ago
passed : expected 3 months ago and got 3 months ago
passed : expected 11 months ago and got 11 months ago
passed : expected one year ago and got one year ago
passed : expected one year ago and got one year ago
passed : expected one year ago and got one year ago
passed : expected one year ago and got one year ago
passed : expected 2 years ago and got 2 years ago