Date.implement({timeDiffInWords:function(to){return Date.distanceOfTimeInWords(this,to||new Date)},timeDiff:function(to,separator){if(to==null){to=new Date}var delta=((to-this)/1000).floor().abs();var vals=[],durations=[60,60,24,365,0],names=["s","m","h","d","y"],value,duration;for(var item=0;item<durations.length;item++){if(item&&!delta){break}value=delta;if((duration=durations[item])){value=(delta%duration);delta=(delta/duration).floor()}vals.unshift(value+(names[item]||""))}return vals.join(separator||":")}}).extend({distanceOfTimeInWords:function(from,to){return Date.getTimePhrase(((to-from)/1000).toInt())},getTimePhrase:function(delta){var suffix=(delta<0)?"Until":"Ago";if(delta<0){delta*=-1}var units={minute:60,hour:60,day:24,week:7,month:52/12,year:12,eon:Infinity};var msg="lessThanMinute";for(var unit in units){var interval=units[unit];if(delta<1.5*interval){if(delta>0.75*interval){msg=unit}break}delta/=interval;msg=unit+"s"}delta=delta.round();return Date.getMsg(msg+suffix,delta).substitute({delta:delta})}}).defineParsers({re:/^(?:tod|tom|yes)/i,handler:function(bits){var d=new Date().clearTime();switch(bits[0]){case"tom":return d.increment();case"yes":return d.decrement();default:return d}}},{re:/^(next|last) ([a-z]+)$/i,handler:function(bits){var d=new Date().clearTime();var day=d.getDay();var newDay=Date.parseDay(bits[2],true);var addDays=newDay-day;if(newDay<=day){addDays+=7}if(bits[1]=="last"){addDays-=7}return d.set("date",d.getDate()+addDays)}}).alias("timeAgoInWords","timeDiffInWords");