2 * Timeago is a jQuery plugin that makes it easy to support automatically
3 * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
7 * @requires jQuery v1.2.3+
9 * @license MIT License - http://www.opensource.org/licenses/mit-license.php
11 * For usage and examples, visit:
12 * http://timeago.yarp.com/
14 * Copyright (c) 2008-2012, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
17 $.timeago = function(timestamp) {
18 if (timestamp instanceof Date) {
19 return inWords(timestamp);
20 } else if (typeof timestamp === "string") {
21 return inWords($.timeago.parse(timestamp));
22 } else if (typeof timestamp === "number") {
23 return inWords(new Date(timestamp));
25 return inWords($.timeago.datetime(timestamp));
38 suffixFromNow: "from now",
39 seconds: "less than a minute",
40 minute: "about a minute",
41 minutes: "%d minutes",
42 hour: "about an hour",
43 hours: "about %d hours",
46 month: "about a month",
53 translator: function(str) {}
55 inWords: function(distanceMillis) {
56 var $l = this.settings.strings;
57 var prefix = $l.prefixAgo;
58 var suffix = $l.suffixAgo;
59 if (this.settings.allowFuture) {
60 if (distanceMillis < 0) {
61 prefix = $l.prefixFromNow;
62 suffix = $l.suffixFromNow;
66 var seconds = Math.abs(distanceMillis) / 1000;
67 var minutes = seconds / 60;
68 var hours = minutes / 60;
69 var days = hours / 24;
70 var years = days / 365;
72 function substitute(stringOrFunction, number) {
73 var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
74 var value = ($l.numbers && $l.numbers[number]) || number;
75 return string.replace(/%d/i, value);
78 var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
79 seconds < 90 && substitute($l.minute, 1) ||
80 minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
81 minutes < 90 && substitute($l.hour, 1) ||
82 hours < 24 && substitute($l.hours, Math.round(hours)) ||
83 hours < 42 && substitute($l.day, 1) ||
84 days < 30 && substitute($l.days, Math.round(days)) ||
85 days < 45 && substitute($l.month, 1) ||
86 days < 365 && substitute($l.months, Math.round(days / 30)) ||
87 years < 1.5 && substitute($l.year, 1) ||
88 substitute($l.years, Math.round(years));
90 var separator = $l.wordSeparator === undefined ? " " : $l.wordSeparator;
91 return $.trim([prefix, words, suffix].join(separator));
93 parse: function(iso8601) {
94 var s = $.trim(iso8601);
95 s = s.replace(/\.\d\d\d+/,""); // remove milliseconds
96 s = s.replace(/-/,"/").replace(/-/,"/");
97 s = s.replace(/T/," ").replace(/Z/," UTC");
98 s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
101 datetime: function(elem) {
102 var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
103 return $t.parse(iso8601);
105 isTime: function(elem) {
106 // jQuery's `is()` doesn't play well with HTML5 in IE
107 return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
111 $.fn.timeago = function() {
115 var $s = $t.settings;
116 if ($s.refreshMillis > 0) {
117 setInterval(function() { self.each(refresh); }, $s.refreshMillis);
123 var data = prepareData(this);
124 if (!isNaN(data.datetime)) {
125 $(this).text(inWords(data.datetime));
130 function prepareData(element) {
131 element = $(element);
132 if (!element.data("timeago")) {
133 element.data("timeago", { datetime: $t.datetime(element) });
134 var text = $.trim(element.text());
135 if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
136 element.attr("title", text);
139 return element.data("timeago");
142 function inWords(date) {
143 return $t.inWords(distance(date));
146 function distance(date) {
147 return (new Date().getTime() - date.getTime());
150 // fix for IE6 suckage
151 document.createElement("abbr");
152 document.createElement("time");