Determining how long ago a page was last edited

I'm making a function that takes the date a page was last edited, accessed through MediaWiki's API, compares it to the current date, and returns how long ago the page was edited, e.g. 1 year/2 days/etc.

It's essentially a massive if/else statement, and I was wondering if there was a better way to implement it.

var timestamp,
utcArr,
today,
utcArr = [],
timestamp2,
timestamp3,
timestamp4,
i,
mwArr = [],
lastEdited;

today = new Date();
utcArr.push(today.getUTCFullYear());
utcArr.push(today.getUTCMonth() + 1); // returns value 0-11
utcArr.push(today.getUTCDate());
utcArr.push(today.getUTCHours());
utcArr.push(today.getUTCMinutes());

/**
* Time function
* For formatting the returned value for timestamp
* example timestamp var: '2013-04-27T14:29:53Z'
*/
function time() {
timestamp2 = timestamp.replace(/(\:|T|Z)/g, '-'); // use g to replace every occurrence, not just one
timestamp3 = timestamp2.split('-');
timestamp4 = timestamp3.filter(function (e) { // remove what's left from Z
return e;
});
for (i = 0; i < timestamp4.length; i++) {
mwArr.push(parseFloat(timestamp4[i]));
}

/**
* Compares dates in array and produces the difference between them
* @todo Find a better way to do this
*/
if ((utcArr[0] - mwArr[0]) === 0) { // years
if ((utcArr[1] - mwArr[1]) === 0) { // months
if ((utcArr[2] - mwArr[2]) === 0) { // days
if ((utcArr[3] - mwArr[3]) === 0 { // hours
if ((utcArr[4] - mwArr[4]) === 0) { // minutes
lastEdited = '1 minute';
} else {
lastEdited = utcArr[4] - mwArr[4] + ' minutes';
}
} else if ((utcArr[3] - mwArr[3]) === 1 && (utcArr[4] - mwArr[4]) < 59) {
lastEdited = utcArr[4] - mwArr[4] + ' minutes';
} else if ((utcArr[3] - mwArr[3]) === 1) {
lastEdited = '1 hour';
} else {
lastEdited = utcArr[3] - mwArr[3] + ' hours';
}
} else if ((utcArr[2] - mwArr[2]) === 1 && (utcArr[3] - mwArr[3]) < 24) {
lastEdited = utcArr[3] - mwArr[3] + ' hours';
} else if ((utcArr[2] - mwArr[2]) === 1) {
lastEdited = 1 day
} else {
lastEdited = utcArr[2] - mwArr[2] + ' days';
}
} else if ((utcArr[1] - mwArr[1]) === 1 && (utcArr[2] - mwArr[2]) < 30) { // we'll just use 30 as it's easier than coding in each month individually
lastEdited = utcArr[2] - mwArr[2] + ' days';
} else if ((utcArr[1] - mwArr[1]) === 1) {
lastEdited = '1 month';
} else {
lastEdited = utcArr[1] - mwArr[1] + ' months';
}
} else if ((utcArr[0] - mwArr[0]) === 1 && (utcArr[1] - mwArr[1]) < 12 ) {
lastEdited = utcArr[1] - mwArr[1] + ' months';
} else if ((utcArr[0] - mwArr[0]) === 1) {
lastEdited = '1 year'
} else {
lastEdited = utcArr[0] - mwArr[0] + ' years';
}

// empty the array or everything turns out the same
mwArr.length = 0;
}


The time function is used about half a dozen times within an AJAX request which returns the edit date in the format "2013-04-27T14:29:53Z" which is used in the function to return lastEdited which is then appended to various ids in a table. I've yet to add complete support for 1 day/month/etc. but that'll just be adding in more if/else statements.

I did consider nested switch statements, but wasn't quite sure how to go about it.

1 Answer

I looked at the source code of moment.js for inspiration:

http://momentjs.com/

And I'm trying to be as declarative as possible, using data to define the time-units I want to use:

unitMillisecondFactors = {
'Millisecond': 1000,
'Second': 60,
'Minute': 60,
'Hour': 24,
'Day': 356,
'Year': 10,
'Decade': 1
};


The Javascript Date object can compute the difference between two timestamps in milliseconds. Looking at such a difference the algorithm goes like this: we currently have units Milliseconds. The factor for getting from milliseconds to seconds is 1000. is the number we'er looking at smaller then that factor? Then we're done, we return a result by rounding down and appending the unit. If we're not done, then we devide the number by the factor and try with the next unit.

function compute_time(timestamp) {
var n = new Date() - new Date(timestamp);
for (var unit in unitMillisecondFactors) {
var factor = unitMillisecondFactors[unit];
if (n < factor) {
n = Math.floor(n);
if (n == 1) {
return s + "more than " + n + " " + unit + " ago\n";
}
else {
return s + "more than " + n + " " + unit + "s ago\n";
}
}
n = n / factor;
}
}


That's it. See http://jsfiddle.net/bjelline/S23V2/ for a working example with some extra output to see the steps of computation.