1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/*** * Beautify date to how recent the event occurred compared to now. * Some examples: 1 second, 4 hours, 10 days, 1 year. * Example: * var oneFiftyMin = new Date(new Date().getTime() - 60000 * 150); * alert(oneFiftyMin.when()); // will display "2 hours" * * Handy for things like "Item posted " + someDate.when() + " ago." */ Date.prototype.when = function() { var diff = new Date().getTime() - this.getTime(); var when; // our return value //TODO: what if the time is in the future? //if (diff < 0) throw new Error ("Date is in future, check timezone?"; //one or more of these will be non-zero, but we only care about the biggest one (in scale of time) var secondsOld = Math.floor(diff / 1000); var minutesOld = Math.floor(diff / 60000); var hoursOld = Math.floor(diff / 3600000); var daysOld = Math.floor(diff / 86400000); var monthsOld = Math.floor(diff / 2592000000); var yearsOld = Math.floor(diff / (2592000000 * 12)); //your content is old! //determine which value is non-zero and assign appropriate text if (yearsOld > 0) { when = yearsOld + " year"; } else if (monthsOld > 0) { when = monthsOld + " month"; } else if (daysOld > 0) { when = daysOld + " day"; } else if (hoursOld > 0) { when = hoursOld + " hour"; } else if (minutesOld > 0) { when = minutesOld + " minute"; } else { when = Math.round(diff /1000) + " second"; } //add plural if necessary return (0 == when.indexOf("1 ")) ? when : when + "s"; }
Refactorings
No refactoring yet !
typefreak
October 1, 2007, October 01, 2007 13:56, permalink
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/*** * Beautify date to how recent the event occurred compared to now. * Some examples: 1 second, 4 hours, 10 days, 1 year. * Example: * var oneFiftyMin = new Date(new Date().getTime() - 60000 * 150); * alert(oneFiftyMin.when()); // will display "2 hours" * * Handy for things like "Item posted " + someDate.when() + " ago." */ Date.prototype.when = function() { var diff = new Date().getTime() - this.getTime(); var when; // our return value //TODO: what if the time is in the future? //if (diff < 0) throw new Error ("Date is in future, check timezone?"; //one or more of these will be non-zero, but we only care about the biggest one (in scale of time) if (diff > (2592000000 * 12) ) { when = Math.floor(diff/(2592000000 * 12)) + " Year"; } else if (diff > 2592000000) { when = Math.floor(diff/2592000000) + " Month"; } else if (diff > 86400000) { when = Math.floor(diff/86400000) + " Day"; } else if (diff > 3600000) { when = Math.floor(diff/3600000) + " Hour"; } else if (diff > 60000) { when = Math.floor(diff/60000) + " Minute"; } else if (diff > 1000) { when = Math.floor(diff/1000) + " Second"; } //add plural if necessary return (0 == when.indexOf("1 ")) ? when : when + "s"; }
Andre Steenveld
October 1, 2007, October 01, 2007 18:17, permalink
First submission hope you like it =)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Date.prototype.when = function( ){ // Create some string consisting of a number and a unit for it. If the // number is smaller than 0 we are not going to return anything. In case the // number is 1 were not going to append a extra "s" to the unit. When the // number is greater than 1 we'll stick an extra s to the unit. function createGroup( no, unit ){ return no > 0 ? " " + ( no > 1 ? no.toString() + " " + unit.toString() + "s" : no.toString() + " " + unit.toString() ) : ""; } var diff = new Date( ( new Date() ).getTime() ); return ( createGroup( diff.getYear(), "year" ) + createGroup( diff.getMonth() + 1, "month" ) + createGroup( diff.getDate(), "day" ) + createGroup( diff.getHours(), "hour" ) + createGroup( diff.getMinutes(), "minute" ) + createGroup( diff.getSeconds(), "second" ) + createGroup( diff.getMilliseconds(), " millisecond" ) ); };
furtive
October 1, 2007, October 01, 2007 18:28, permalink
Wow guys, I'm impressed! Typefreak's does a great job in being efficient operationally while Andre's appears to do the best job at exploiting the Date object itself. I'm impressed!
Andre Steenveld
October 1, 2007, October 01, 2007 18:32, permalink
Didn't test it properly here is a "fixed" version...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Date.prototype.when = function( ){ // Create some string consisting of a number and a unit for it. If the // number is smaller than 0 we are not going to return anything. In case the // number is 1 were not going to append a extra "s" to the unit. When the // number is greater than 1 we'll stick an extra s to the unit. function createGroup( no, unit ){ return no > 0 ? " " + ( no > 1 ? no.toString() + " " + unit.toString() + "s" : no.toString() + " " + unit.toString() ) : ""; } var diff = new Date( ( new Date() ).getTime() - this.getTime() ); return ( createGroup( diff.getFullYear() - 1970, "year" ) + createGroup( diff.getMonth(), "month" ) + createGroup( diff.getDate() - 1, "day" ) + createGroup( diff.getHours() - 1, "hour" ) + createGroup( diff.getMinutes() - 1, "minute" ) + createGroup( diff.getSeconds() - 1, "second" ) + createGroup( diff.getMilliseconds() - 1, " millisecond" ) ); };
Tomasz Kołodziejski
October 2, 2007, October 02, 2007 06:09, permalink
I'm not sure if it works, but here's a different idea:
1 2 3 4 5 6 7 8 9 10
Date.prototype.when = function(){ var diff = (new Date() - this)/1e3; var a = {'second':60, 'minute':60, 'hour':24, 'day':30, 'month':365, 'year':365}; // a small hack here - won't display correctly if difference > 365 years for(var i in a){ diff/=a[i]; if(diff<1){ return Math.floor(diff*=a[i])+' '+i+(diff>1?'s':0); } } }
Andre Steenveld
October 2, 2007, October 02, 2007 14:02, permalink
I was very very impressed by Tomasz's idea so I worked it out. I used two arrays instead of an object because there is no way to guarantee how a for-in loop will itterate through an object. You can shave off another line by putting unit and size in one array and using split() to get your int or your unit name.
1 2 3 4 5 6 7 8 9 10 11
Date.prototype.when = function(){ var diff = ( ( new Date(0) ).getTime() - this.getTime() ) / 1000, units = [ "second", "minute", "hour", "day", "weeks", "month", "year" ], size = [ 1, 60, 60, 24, 7, 4.333, 12 ]; for( var i = 0; i < units.length; i++ ){ diff /= size[ i ]; if( diff < 1 ) return Math.floor( diff *= size[ i ] ) + " " + units[ i - 1 ] + ( diff > 1 ? "s" : "" ); } };
Andre Steenveld
October 2, 2007, October 02, 2007 16:06, permalink
Any short than this would be impossible i think...
1 2 3 4 5 6 7 8 9
Date.prototype.when = function(){ var diff = ( ( new Date(0) ).getTime() - this.getTime() ) / 1000, units = [ "60|second", "60|minute", "24|hour", "7|day", "4.333|week", "12|month", "1|year" ]; for( var i = 0; i < units.length && !( diff < 1 || ( i + 1 ) === units.length ); i++ ) diff /= units[ i ].split("|")[ 0 ]; return Math.floor( diff *= units[ i ].split("|")[ 0 ] ) + " " + units[ i ].split("|")[ 1 ] + ( diff > 1 ? "s" : "" ) + "[ " + i + " ]"; };
Tomasz `neo` Kołodziejski
October 3, 2007, October 03, 2007 06:20, permalink
I think that using the getTime function isn't necessary. Separating these two arrays would be much better I think and easier to modifying. In the 8 line we can use ~~.
1 2 3 4 5 6 7 8 9 10 11 12 13
Date.prototype.when = function(){ var diff = (new Date() - this)/1e3, u = [ "second", "minute", "hour", "day", "weeks", "month", "year" ], s = [ 1, 60, 60, 24, 7, 4.333, 12, 1e9], // again fast hack - 1e9 i=0; for(;;i++){ if((diff/=s[i])<1){ return ~~(diff*=s[i])+' '+u[i-1]+(diff>1?'s':0); } } }
richardhealy
October 12, 2007, October 12, 2007 09:15, permalink
Tomasz! Nice little bit of javascript there. Trying to search for some tuts on the "~~" and I'm not finding anything... Does anyone know where I can find out more about it? What does it do?
Andre Steenveld
October 17, 2007, October 17, 2007 11:38, permalink
It's a bitwise operation what i basically does in this situation is cut of evrything after the decimal point.
hubfactor
February 7, 2008, February 07, 2008 18:22, permalink
Hope the date's not in the future...
1 2 3 4 5 6 7 8 9
Date.prototype.when = function(){ var diff = (new Date() - this) / 1e3; var u = [ "second", "minute", "hour", "day", "week", "month", "year" ]; var s = [ 1, 60, 60, 24, 7, 4.333, 12, 1e9 ]; // 1e9 = hack for speed for (var i in s) if ((diff /= s[i]) < 1) return ~~ (diff *= s[i]) + " " + u[i-1] + (diff > 1 ? "s" : ""); }
This adds a .when() method to Date() object allowing you do things such as "Posted " + someDate.when() + " ago." and get output such as "Posted 10 minutes ago." I've refactored it twice but would like to see it even smaller.