Avatar

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.

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 !

A2c8fecfd1fb707dd0a8f292ade77e1e

typefreak

October 1, 2007, October 01, 2007 13:56, permalink

No rating. Login to rate!
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";
}
7ab05ae02bbc7401f852d586bba1afc2

Andre Steenveld

October 1, 2007, October 01, 2007 18:17, permalink

No rating. Login to rate!

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" )
	);
};
Avatar

furtive

October 1, 2007, October 01, 2007 18:28, permalink

No rating. Login to rate!

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!

7ab05ae02bbc7401f852d586bba1afc2

Andre Steenveld

October 1, 2007, October 01, 2007 18:32, permalink

No rating. Login to rate!

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" )
	);
};
49e7b222e3512728f1a28293fb451ec1

Tomasz Kołodziejski

October 2, 2007, October 02, 2007 06:09, permalink

1 rating. Login to rate!

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);
		}
	}
}
7ab05ae02bbc7401f852d586bba1afc2

Andre Steenveld

October 2, 2007, October 02, 2007 14:02, permalink

No rating. Login to rate!

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" : "" );	
    }
};
7ab05ae02bbc7401f852d586bba1afc2

Andre Steenveld

October 2, 2007, October 02, 2007 16:06, permalink

No rating. Login to rate!

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 + " ]";
};
Avatar

Tomasz `neo` Kołodziejski

October 3, 2007, October 03, 2007 06:20, permalink

2 ratings. Login to rate!

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);
		}
	}
	
}
28e65a85a625f7c0689bcf96ccf6043d

richardhealy

October 12, 2007, October 12, 2007 09:15, permalink

No rating. Login to rate!

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?

Avatar

Andre Steenveld

October 17, 2007, October 17, 2007 11:38, permalink

No rating. Login to rate!

It's a bitwise operation what i basically does in this situation is cut of evrything after the decimal point.

Ed9c50a6db8b5e078b5ef84306a8477c

hubfactor

February 7, 2008, February 07, 2008 18:22, permalink

No rating. Login to rate!

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" : "");
}

Your refactoring





Format Copy from initial code

or Cancel