Saturday, February 12, 2011

Facebook created_time format in JSON response

I was trying to get relative times for Facebook posts for fbbash, using the time returned in JSON objects using the Facebook JavaScript SDK. The created_time looks something like 2011-02-12T11:58:46+0000

The part before the 'T' is the date in a 'YYYY-MM-DD' format. And after is the time in 'HH:MM:SS'. As far as I can tell, the trailing '+0000' is the timezone offset but I've only ever seen that value so I've made the assumption that you're getting times that are GMT more or less (or UTC if you want to get technical).

I found this script on Stack Overflow by no, that converts this timestamp into a relative time string such as '5 min ago'. Unfortunately, despite what the comments on the script say, simply calling
fuzzyFacebookTime('2011-02-12T11:58:46+0000'); //doesn't work!
doesn't return the right value - instead, it gives back 'NaN years ago'.

The easy fix to this problem is to change the timestamp you're passing to the function to the form YYYY/MM/DDTHH:MM:SS+ZZZZ i.e. change the hyphens (-) to slashes (/). That seems to work and you should get the correct string. So you can make the call
fuzzyFacebookTime('2011-02-12T11:58:46+0000'.replace(/-/g,'/'));

Here's the script:
var fuzzyFacebookTime = (function(){

  fuzzyTime.defaultOptions={
    // time display options
    relativeTime : 48,
    // language options
    monthNames : ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
    amPm : ['AM', 'PM'],
    ordinalSuffix : function(n) {return ['th','st','nd','rd'][n<4 || (n>20 && n % 10<4) ? n % 10 : 0]}
  }

  function fuzzyTime (timeValue, options) {

    var options=options||fuzzyTime.defaultOptions, 
        date=parseDate(timeValue),
        delta=parseInt(((new Date()).getTime()-date.getTime())/1000),
        relative=options.relativeTime,
        cutoff=+relative===relative ? relative*60*60 : Infinity;

    if (relative===false || delta>cutoff)
      return formatTime(date, options)+' '+formatDate(date, options);

    if (delta<60) return 'less than a minute ago';
    var minutes=parseInt(delta/60 +0.5);
    if (minutes <= 1) return 'about a minute ago';
    var hours=parseInt(minutes/60 +0.5);
    if (hours<1) return minutes+' minutes ago';
    if (hours==1) return 'about an hour ago';
    var days=parseInt(hours/24 +0.5);
    if (days<1) return hours+' hours ago';
    if (days==1) return formatTime(date, options)+' yesterday';
    var weeks=parseInt(days/7 +0.5);
    if (weeks<2) return formatTime(date, options)+' '+days+' days ago';
    var months=parseInt(weeks/4.34812141 +0.5);
    if (months<2) return weeks+' weeks ago';
    var years=parseInt(months/12 +0.5);
    if (years<2) return months+' months ago';
    return years+' years ago';
  }

  function parseDate (str) {
    var v=str.replace(/[T\+]/g,' ').split(' ');
    return new Date(Date.parse(v[0] + " " + v[1] + " UTC"));
  }

  function formatTime (date, options) {
    var h=date.getHours(), m=''+date.getMinutes(), am=options.amPm;
    return (h>12 ? h-12 : h)+':'+(m.length==1 ? '0' : '' )+m+' '+(h<12 ? am[0] : am[1]);
  }

  function formatDate (date, options) {
    var mon=options.monthNames[date.getMonth()],
        day=date.getDate(),
        year=date.getFullYear(),
        thisyear=(new Date()).getFullYear(),
        suf=options.ordinalSuffix(day);

    return mon+' '+day+suf+(thisyear!=year ? ', '+year : '');
  }

  return fuzzyTime;

}());
Image Credit: ThinkDiff.net

 UPDATE [1235 20 Feb 2011]: Added an image and fixed some formatting

4 comments:

madturki said...

Thank you!

Devra Johnson said...

Thanks a lot. Instead of using .replace(/-/g,'/')) on your input, you can change line 45 of the code to:

return new Date(Date.parse(v[0].replace(/-/g,'/')) + " " + v[1] + " UTC"));

Anonymous said...

help me please? Im getting Nan years ago

Carlos Henrique Lustosa said...

Works fine!
Thanks =]