views:

1525

answers:

5

Below is a really nice time ago plugin for jQuery, very similar to what they use here on SO. The problem for me is that it uses this to convert time.

<time class="timeago" datetime="2008-07-17T09:24:17Z">July 17, 2008</time>

That would be great except that I store time on my site in UTC timestamp and not as a formatted time, is there a way to convert something like this to use a timestamp? I know in PHP I could convert my timestamp to this format but it seems like overkill with converting a LOT of times on 1 page in PHP. I could be wrong, anyone else do this in jquery but from real timestamp?

Also I currently do this in PHP on a site to show "2 hours 4 minutes ago" but wou7ld it be better to use javascript for this instead of PHP?

/*
 * timeago: a jQuery plugin, version: 0.8.1 (2010-01-04)
 * @requires jQuery v1.2.3 or later
 *
 * Timeago is a jQuery plugin that makes it easy to support automatically
 * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
 *
 * For usage and examples, visit:
 * http://timeago.yarp.com/
 * Copyright (c) 2008-2010, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
 */
(function($) {
  $.timeago = function(timestamp) {
    if (timestamp instanceof Date) return inWords(timestamp);
    else if (typeof timestamp == "string") return inWords($.timeago.parse(timestamp));
    else return inWords($.timeago.datetime(timestamp));
  };
  var $t = $.timeago;

  $.extend($.timeago, {
    settings: {
      refreshMillis: 60000,
      allowFuture: false,
      strings: {
        prefixAgo: null,
        prefixFromNow: null,
        suffixAgo: "ago",
        suffixFromNow: "from now",
        ago: null, // DEPRECATED, use suffixAgo
        fromNow: null, // DEPRECATED, use suffixFromNow
        seconds: "less than a minute",
        minute: "about a minute",
        minutes: "%d minutes",
        hour: "about an hour",
        hours: "about %d hours",
        day: "a day",
        days: "%d days",
        month: "about a month",
        months: "%d months",
        year: "about a year",
        years: "%d years"
      }
    },
    inWords: function(distanceMillis) {
      var $l = this.settings.strings;
      var prefix = $l.prefixAgo;
      var suffix = $l.suffixAgo || $l.ago;
      if (this.settings.allowFuture) {
        if (distanceMillis < 0) {
          prefix = $l.prefixFromNow;
          suffix = $l.suffixFromNow || $l.fromNow;
        }
        distanceMillis = Math.abs(distanceMillis);
      }

      var seconds = distanceMillis / 1000;
      var minutes = seconds / 60;
      var hours = minutes / 60;
      var days = hours / 24;
      var years = days / 365;

      var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
        seconds < 90 && substitute($l.minute, 1) ||
        minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
        minutes < 90 && substitute($l.hour, 1) ||
        hours < 24 && substitute($l.hours, Math.round(hours)) ||
        hours < 48 && substitute($l.day, 1) ||
        days < 30 && substitute($l.days, Math.floor(days)) ||
        days < 60 && substitute($l.month, 1) ||
        days < 365 && substitute($l.months, Math.floor(days / 30)) ||
        years < 2 && substitute($l.year, 1) ||
        substitute($l.years, Math.floor(years));

      return $.trim([prefix, words, suffix].join(" "));
    },
    parse: function(iso8601) {
      var s = $.trim(iso8601);
      s = s.replace(/-/,"/").replace(/-/,"/");
      s = s.replace(/T/," ").replace(/Z/," UTC");
      s = s.replace(/([\+-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
      return new Date(s);
    },
    datetime: function(elem) {
      // jQuery's `is()` doesn't play well with HTML5 in IE
      var isTime = $(elem).get(0).tagName.toLowerCase() == 'time'; // $(elem).is('time');
      var iso8601 = isTime ? $(elem).attr('datetime') : $(elem).attr('title');
      return $t.parse(iso8601);
    }
  });

  $.fn.timeago = function() {
    var self = this;
    self.each(refresh);

    var $s = $t.settings;
    if ($s.refreshMillis > 0) {
      setInterval(function() { self.each(refresh); }, $s.refreshMillis);
    }
    return self;
  };

  function refresh() {
    var data = prepareData(this);
    if (!isNaN(data.datetime)) {
      $(this).text(inWords(data.datetime));
    }
    return this;
  }

  function prepareData(element) {
    element = $(element);
    if (element.data("timeago") === undefined) {
      element.data("timeago", { datetime: $t.datetime(element) });
      var text = $.trim(element.text());
      if (text.length > 0) element.attr("title", text);
    }
    return element.data("timeago");
  }

  function inWords(date) {
    return $t.inWords(distance(date));
  }

  function distance(date) {
    return (new Date().getTime() - date.getTime());
  }

  function substitute(stringOrFunction, value) {
    var string = $.isFunction(stringOrFunction) ? stringOrFunction(value) : stringOrFunction;
    return string.replace(/%d/i, value);
  }

  // fix for IE6 suckage
  document.createElement('abbr');
  document.createElement('time');
})(jQuery);
A: 

It would be better using both, but it is not necessary to make it dynamic with JS.

In fact, I've only seen this behaviour in Facebook.

Also, are you well aware that the <time> tag is HTML5? It may create a few uncompatibilities.

metrobalderas
+2  A: 

I like to use DateJS.com which is a date / time javascript library. You can do cool stuff like this (display 2 hours ago in a <span id='myfield'></span>):

$('#myfield').text( (2).hours().ago().toString("HH:mm") );
Keltex
+1  A: 
jsumners
A: 

I had the same problem. I'm using Unix timestamps which are generated from PHP, so I decided to do a quick hack and extend the parsing function of jQuery timeago to handle timestamps additionally. Works like a charm. Simply look for the Parse function at around line 79 in the jquery.timeago.js file, and replace with the following:

  parse: function(iso8601) {
  if ((iso8601 - 0) == iso8601 && iso8601.length > 0) { // Checks if iso8601 is a unix timestamp
    var s = new Date(iso8601);
    if (isNaN(s.getTime())) { // Checks if iso8601 is formatted in milliseconds
      var s = new Date(iso8601 * 1000); //if not, add milliseconds 
    }
    return s;
  }

  var s = $.trim(iso8601);
  s = s.replace(/-/,"/").replace(/-/,"/");
  s = s.replace(/T/," ").replace(/Z/," UTC");
  s = s.replace(/([\+-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
  return new Date(s);
},
Hal
A: 

Take a look at this jquery plugin which seems to do exactly what you want.

http://timeago.yarp.com/

balu