Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

smarter and improved #9

Closed
wants to merge 15 commits into from

6 participants

@fent

I've added several new options to this library. All of them include tests and there is documentation in the readme for them.

$.fn.timeago.defaults = {
  // The default attribute to put the ISO8601 absolute time to parse.
  attr: 'datetime',

  // An extra space character will be added between the time and the unit.
  // '1 minute' will look like '1minute' with spacing set to `false`.
  spacing: true,

  // Will enable displaying text approximation words
  // such as 'about 1 hour' and 'almost 2 years'.
  approximate: true,

  // The text generated by Smart Time Ago will look like '3 hours ago'.
  // If you want the text looks like '3 hours from now',
  // you might need change the 'suffix' to ' from now'.
  suffix: ' ago',

  // Will show how many seconds. Instead of 'less than a minute ago' you'll see '24 seconds ago'.
  showSeconds: false,

  // You can specify how many seconds, below 59, to show a 'just now' message
  // instead of '1 second ago'.
  showNow: false,

  // After a date's relative time is too big,
  // you might want to display its absolute version.
  // For example, if after one month you don't want to display '2 years ago',
  // you can make `maxRelative` equal `2592000` which is a month in seconds.
  // Then specify an absolute displaying date function.
  maxRelative: false,
  absoluteDate: function(date, datetime) { return datetime; }
};

If you notice, I also removed the dir and selector options, because those are not needed. jQuery already has a selector engine, and it's already possible to call timeago on dynamically added elements. It makes much more sense for the user to be able to select what elements to use with time ago like this

$('.timeago').timeago();

instead of

$('body').timeago();

Also, this way, each of the elements get their own TimeAgo instance, and therefore their own timeout. I didn't really understand why the dir option was needed, it would mean that every single date for that instance would be updated even unnecessarily, which I think goes in the wrong direction if we want this to be smart.

Also, I made this much smarter. The timeouts are now set to go off exactly when the relative date will change, and not before or much much after. Being more accurate with timeouts is smarter. :)

@poshboytl
Owner

Thanks for the big PR. :D Very busy these days. So didn't get a chance to review all the stuff.
Will dig into it latter.
Thanks again.

@fent

No problem. We're all busy. :)

@fent

Any update on merging this?

@andreoav

@fent This works with languages that "ago" is a prefix? See #7
There's no "prefix" option in the new plugin defaults.

@andreoav

Oh! Ok. I was looking at the wrong place.

@t3chn0r

Thanks @fent, awesome changes!

@t3chn0r

@fent, I was just working with your new version and for some reason iOS devices were failing with an error. I traced the error to the bind in TimeAgo.prototype.startTimer, it seems bind() is not supported in iOS and it gives a weird error saying "undefined is not a function". I just replaced the code with the original (a function() containing just a return self.refresh()) and everything seems to be working fine now.

@fent

Thank you good catch @t3chn0r

@hatemalimam

I used this plugin which is working perfectly, BUT you have to apply the timezone because it compare the returned date by the computer date since it's javascript.

maybe you can help me with thinking. I have two cases the first case where I calculate timeago on server (PHP) and the second case where I calculate the timeago by this javascript plugin which update the time each minute.

the first case is more solid, why because since the date on the server is always UTC and the returned date will be UTC it will always calculate right, but I will lose the nice self-updating functionality.
the second case is more fun, but I have to return the date in locale timezone of the user who is selected on his profile.
for example the user has to go to his profile and select his right timezone to make this plugin works right, and if the time on his computer is not accurate it won't calculate right (since I noticed that the comparison is based on the OS Clock) which is returned by Javascript ....
to prove this, I changed the clock of the mac 5 minutes back, and when the plugin updated the values it toke the dates 5 minutes back !!

BTW, I'm no Javascript Expert, just a normal developer who wants the best for this plugin (an option to pass the current time to compare based on it)

Thank you.

@fent

I think it expects a date formatted as ISO8601. You can print your dates in that format with PHP
http://www.php.net/manual/en/class.datetime.php#datetime.constants.types

No timezone information is required this way.

@hatemalimam

Yes that's exactly what I do, but the problem is in which timezone I have to print the date!!
The server's timezone is UTC, and mine is Europe/Rome which is one hour more than UTC, so let say that I have current time printed and passed to this plugin through time tag it will print 1 hour ago.
I hope you got what I mean.

@hatemalimam

Am I wrong in any point ?

@fent

Hmm that's strange, the timezones we use this with are UTC too, we convert them to ISO strings to pass them to timeago and they work without issues. An example timezone looks like Wed Aug 27 13:08:45 +0000 2008 and we convert that to ISO.

@t3chn0r

I just did a quick test and everything works fine... ISO8601 format is always in UTC and smarttime takes into consideration that when calculating the time passed.

What I did in my quick test:

  • Server is running in Eastern Time (UTC - 5)
  • Value in datetime is stored in ISO8601
  • One machine in same time zone as the server (remember that the date is already in UTC) show 2 minutes ago (just an example)
  • Another computer set to UTC-3 (Buenos Aires, Argentina) shows also 2 minutes ago.
@t3chn0r

Everything works fine because you are passing a UTC time and smarttime is using Date().getTime() which also returns the number of milliseconds since 1970/01/01 00:00:00 UTC...

Date.getTime() doesn't return the amount of milliseconds from 1970/01/01 00:00:00 YOUR-TIMEZONE-HERE

@hatemalimam

Hmmm, that's odd!!
I'll try again un the morning, maybe I'm missing something.
Thank you guys for your help.
I'll reply next thing in the morning.

@hatemalimam

Maybe my way of converting the timestap to iso 8601 is just wrong, I found out this post, I'll try to stick to it and see what happens, anyway I'll reply soon.
Thank you again
And oh an example on this plugin along with php use on the website would be helpfull for others too.
Keep it up. As I said I'll reply soon to confirm.
http://stackoverflow.com/questions/2471832/how-to-convert-a-unix-timestamp-to-an-iso8601-timestamp-in-php

@hatemalimam

now this is the output html

<time class="timeago" datetime="2013-02-01 12:40:05">about 1 hour ago</time>

the datetime is the current time in UTC !!!
Am I missing something here, maybe the formatting of the timestamp ??!!

@t3chn0r

I use date('c') to format the timestamp, the HTML then ends up like <time class="timeago" datetime="2013-02-01T13:55:48+01:00"></time>

The timestamp is obviously generated server side so make sure the server's time, timezone, daylight saving time, etc is set in the correct way.

@hatemalimam

yes that's what I was missing the formatting !!

<?php
public function ISO8601($utcTimestamp) {
        return date("c", strtotime($utcTimestamp));
    }
?>

This function would do the conversion correctly, inorder to display it as expected, thank you man, thanks all.
I think it's a good idea to include this function in the HOW-TO of this plugin in a PHP section code, or just mention that the passed timezone has to be converted to ISO8601.

Grazie a tutti.

@rpocklin

So... what's the status of this PR?

@fent fent Merge remote-tracking branch 'upstream/master'
Conflicts:
	lib/timeago.js
	src/timeago.coffee
2dc0341
@fent

I just merged the latest changes into this PR to keep it up to date, and encourage a faster merge into original repo process.

@fent fent closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 13, 2012
  1. @fent

    added `spacing` option

    fent authored
Commits on Sep 15, 2012
  1. @fent

    add `approximate` option

    fent authored
  2. @fent

    typo

    fent authored
  3. @fent

    fix suffix option

    fent authored
  4. @fent
  5. @fent

    added showSeconds option

    fent authored
  6. @fent

    added showNow option

    fent authored
  7. @fent
  8. @fent
  9. @fent

    clarify rules

    fent authored
  10. @fent
  11. @fent

    using timeout instead of interval

    fent authored
Commits on Jan 7, 2013
  1. @fent

    fix tests

    fent authored
  2. @fent

    dont use Function#bind

    fent authored
Commits on Nov 23, 2013
  1. @fent

    Merge remote-tracking branch 'upstream/master'

    fent authored
    Conflicts:
    	lib/timeago.js
    	src/timeago.coffee
This page is out of date. Refresh to see the latest.
View
89 README.md
@@ -21,80 +21,69 @@ Or if you use node, you can install it from npm.
Why Smart?
-------------
-Smart Time Ago will check and update the relative time every 60000 millisecond (60 seconds) in the scope you specify at the beginning. Latter it will check the newest time in your scope then tune the checking time interval to a proper value.
+Smart Time Ago will check and update the relative time only when it needs to, automatically increasing the timeout time as the given date becomes older.
-For example, if the newest time in the scope you specify is '2 hours ago'. There is no need to check and update the relative time every 60 seconds. Instead, Smart Time Ago will automaticly make the checking time interval longer to 30 minutes.
-
-Rules:
-
- The newest time is less than 44 minutes, the checking time interval will set to 1 minute.
-
- The newest time is between 44 and 89 minutes, the checking time interval will set to 22 minutes.
-
- The newest time is between 90 minutes and 42 hours, the checking time interval will set to 30 minutes.
-
- The newest time is more than 42 hours, the checking time interval will set to half day.
+For example, if the newest time in the scope you specify is '2 hours ago'. There is no need to check and update the relative time every 60 seconds. Instead, Smart Time Ago will automaticly make the checking time timeout to the next time it needs to update.
Usage
------------
-By default Smart Time Ago will keep watching on the time elements with a class of timeago and a ISO8601 timestamp in datatime attribute:
-
- <time class="timeago" datetime="2012-07-18T07:51:50Z">about 8 hours ago</time>
-
-You can initialize the smart-time-ago in global like:
-
- $('body').timeago();
-
-It will watch all your relative time elements by only one TimeAgo instance.
-
-Or you can use it in a specify scope like.
+You can use it in a specify scope like.
<div class="timeLables">
- <time class="timeago" datetime="2012-07-18T07:51:50Z">about 8 hours ago</time>
- <time class="timeago" datetime="2012-07-18T06:51:50Z">about 9 hours ago</time>
+ <div class="timeago" datetime="2012-07-18T07:51:50Z">about 8 hours ago</div>
+ <dic class="timeago" datetime="2012-07-18T06:51:50Z">about 9 hours ago</div>
</div>
- $('.timeLables').timeago();
-
-It will create one TimeAgo instance to update the time elements in the div with timeLables class.
-
-However you can also create TimeAgo instance for every time element separately like:
-
$('.timeago').timeago();
-BTW if you need dynamic add the time element to your document without refreshing the page or you want to refresh the timeago manually. You might need call the refresh function to refresh the instance like:
-
- $('.timeago').timeago('refresh');
+By default, timeago will get the date from the `datetime` attribute. This will create a TimeAgo instance for each of the matched elements that have the required attribute.
-
Configuration
--------------
-There are some default configuration in Smart Time Ago:
+```js
+$.fn.timeago.defaults = {
+ // The default attribute to put the ISO8601 absolute time to parse.
+ attr: 'datetime',
- $.fn.timeago.defaults = {
- selector: 'time.timeago',
- attr: 'datetime',
- dir: 'up',
- suffix: 'ago'
- };
-
-The 'time.timeago' is the default selector to watch and update.
+ // An extra space character will be added between the time and the unit.
+ // '1 minute' will look like '1minute' with spacing set to `false`.
+ spacing: true,
-The 'datetime' is the default attribute to put the ISO8601 absolute time to parse.
+ // Will enable displaying text approximation words
+ // such as 'about 1 hour' and 'almost 2 years'.
+ approximate: true,
-The 'up' in dir means the elements in your scope is display by time desc. which means if the dir sets to 'up'. Smart Time Ago will treat the first element's time as the newest time to adjust the time interval. Oppositely if it set to 'down', Smart Time Ago will treat the last element's time as the newewst time.
+ // The text generated by Smart Time Ago will look like '3 hours ago'.
+ // If you want the text looks like '3 hours from now',
+ // you might need change the 'suffix' to ' from now'.
+ suffix: ' ago',
+ // Will show how many seconds. Instead of 'less than a minute ago' you'll see '24 seconds ago'.
+ showSeconds: false,
-The 'ago' in 'suffix' means the relative generated by Smart Time Ago will look like '3 hours ago'.
-If you want the text looks like '3 hours from now', you might need change the 'suffix' to 'from now'.
+ // You can specify how many seconds, below 59, to show a 'just now' message
+ // instead of '1 second ago'.
+ showNow: false,
+
+ // After a date's relative time is too big,
+ // you might want to display its absolute version.
+ // For example, if after one month you don't want to display '2 years ago',
+ // you can make `maxRelative` equal `2592000` which is a month in seconds.
+ // Then specify an absolute displaying date function.
+ maxRelative: false,
+ absoluteDate: function(date, datetime) { return datetime; }
+};
+```
+
+
+T
You can change the default configurations by passing the options to
timeago function when initialize timeago like:
- $('.timeago').timeago({selector: 'span.timeago', attr: 'title', dir: 'down', suffix: 'from now'})
-
+ $('.timeago').timeago({selector: 'span.timeago', attr: 'title', dir: 'down', suffix: ' from now'})
Gem for Rails
-------------
View
3  lib/locales/timeago.da.js
@@ -1,6 +1,5 @@
-// Generated by CoffeeScript 1.3.3
+// Generated by CoffeeScript 1.6.3
(function() {
-
$.fn.timeago.defaults.lang = {
units: {
second: "sekund",
View
2  lib/locales/timeago.de.js
@@ -1,5 +1,5 @@
+// Generated by CoffeeScript 1.6.3
(function() {
-
$.fn.timeago.defaults.lang = {
units: {
second: "Sekunde",
View
3  lib/locales/timeago.en.js
@@ -1,6 +1,5 @@
-// Generated by CoffeeScript 1.3.3
+// Generated by CoffeeScript 1.6.3
(function() {
-
$.fn.timeago.defaults.lang = {
units: {
second: "second",
View
3  lib/locales/timeago.es.js
@@ -1,6 +1,5 @@
-// Generated by CoffeeScript 1.3.3
+// Generated by CoffeeScript 1.6.3
(function() {
-
$.fn.timeago.defaults.lang = {
units: {
second: "segundo",
View
3  lib/locales/timeago.fr.js
@@ -1,6 +1,5 @@
-// Generated by CoffeeScript 1.3.3
+// Generated by CoffeeScript 1.6.3
(function() {
-
$.fn.timeago.defaults.lang = {
units: {
second: "seconde",
View
3  lib/locales/timeago.ja.js
@@ -1,6 +1,5 @@
-// Generated by CoffeeScript 1.6.1
+// Generated by CoffeeScript 1.6.3
(function() {
-
$.fn.timeago.defaults.lang = {
units: {
second: "",
View
3  lib/locales/timeago.pt-br.js
@@ -1,6 +1,5 @@
-// Generated by CoffeeScript 1.3.3
+// Generated by CoffeeScript 1.6.3
(function() {
-
$.fn.timeago.defaults.lang = {
units: {
second: "segundo",
View
7 lib/locales/timeago.zh-cn.js
@@ -1,6 +1,5 @@
-// Generated by CoffeeScript 1.6.1
+// Generated by CoffeeScript 1.6.3
(function() {
-
$.fn.timeago.defaults.lang = {
units: {
second: "",
@@ -11,8 +10,8 @@
hours: "小时",
day: "",
days: "",
- month: "",
- months: "",
+ month: "个月",
+ months: "个月",
year: "",
years: ""
},
View
185 lib/timeago.js
@@ -1,37 +1,23 @@
-// Copyright 2012, Terry Tai, Pragmatic.ly
-// https://pragmatic.ly/
-// Licensed under the MIT license.
-// https://github.com/pragmaticly/smart-time-ago/blob/master/LICENSE
-//
-// Generated by CoffeeScript 1.5.0
-
+// Generated by CoffeeScript 1.6.3
(function() {
var TimeAgo;
TimeAgo = (function() {
-
function TimeAgo(element, options) {
- this.startInterval = 60000;
- this.init(element, options);
- }
-
- TimeAgo.prototype.init = function(element, options) {
this.$element = $(element);
this.options = $.extend({}, $.fn.timeago.defaults, options);
- this.updateTime();
- return this.startTimer();
- };
+ this.refresh();
+ }
TimeAgo.prototype.startTimer = function() {
- var self;
- self = this;
- return this.interval = setInterval((function() {
- return self.refresh();
- }), this.startInterval);
+ var _this = this;
+ return this.interval = setTimeout(function() {
+ return _this.refresh();
+ }, this.startInterval);
};
TimeAgo.prototype.stopTimer = function() {
- return clearInterval(this.interval);
+ return clearTimeout(this.interval);
};
TimeAgo.prototype.restartTimer = function() {
@@ -45,93 +31,105 @@
};
TimeAgo.prototype.updateTime = function() {
- var self;
- self = this;
- return this.$element.findAndSelf(this.options.selector).each(function() {
- var timeAgoInWords;
- timeAgoInWords = self.timeAgoInWords($(this).attr(self.options.attr));
- return $(this).html(timeAgoInWords);
- });
+ var timeAgoInWords;
+ timeAgoInWords = this.timeAgoInWords(this.$element.attr(this.options.attr));
+ return this.$element.html(timeAgoInWords);
};
TimeAgo.prototype.updateInterval = function() {
- var filter, newestTime, newestTimeInMinutes, newestTimeSrc;
- if (this.$element.findAndSelf(this.options.selector).length > 0) {
- if (this.options.dir === "up") {
- filter = ":first";
- } else if (this.options.dir === "down") {
- filter = ":last";
- }
- newestTimeSrc = this.$element.findAndSelf(this.options.selector).filter(filter).attr(this.options.attr);
- newestTime = this.parse(newestTimeSrc);
- newestTimeInMinutes = this.getTimeDistanceInMinutes(newestTime);
- if (newestTimeInMinutes >= 0 && newestTimeInMinutes <= 44 && this.startInterval !== 60000) {
- this.startInterval = 60000;
- return this.restartTimer();
- } else if (newestTimeInMinutes >= 45 && newestTimeInMinutes <= 89 && this.startInterval !== 60000 * 22) {
- this.startInterval = 60000 * 22;
- return this.restartTimer();
- } else if (newestTimeInMinutes >= 90 && newestTimeInMinutes <= 2519 && this.startInterval !== 60000 * 30) {
- this.startInterval = 60000 * 30;
- return this.restartTimer();
- } else if (newestTimeInMinutes >= 2520 && this.startInterval !== 60000 * 60 * 12) {
- this.startInterval = 60000 * 60 * 12;
- return this.restartTimer();
- }
+ var dis, newestTime, newestTimeSrc;
+ newestTimeSrc = this.$element.attr(this.options.attr);
+ newestTime = this.parse(newestTimeSrc);
+ dis = this.getTimeDistanceInSeconds(newestTime);
+ if (this.options.maxRelative && dis >= this.options.maxRelative) {
+ return this.stopTimer();
+ } else if (this.options.showNow && dis < this.options.showNow) {
+ this.startInterval = (this.options.showNow - dis) * 1000;
+ return this.restartTimer();
+ } else if (this.options.showSeconds && dis < 60) {
+ this.startInterval = 1000;
+ return this.restartTimer();
+ } else if (dis < 2700) {
+ this.startInterval = (60 - dis % 60) * 1000;
+ return this.restartTimer();
+ } else if (dis < 5400) {
+ this.startInterval = (5400 - dis) * 1000;
+ return this.restartTimer();
+ } else if (dis < 151200) {
+ this.startInterval = (3600 - dis % 3600) * 1000;
+ return this.restartTimer();
+ } else {
+ this.startInterval = (86400 - dis % 86400) * 1000;
+ return this.restartTimer();
}
};
TimeAgo.prototype.timeAgoInWords = function(timeString) {
- var absolutTime;
+ var absolutTime, dis;
absolutTime = this.parse(timeString);
- return "" + this.options.lang.prefixes.ago + (this.distanceOfTimeInWords(absolutTime)) + this.options.lang.suffix;
+ dis = this.getTimeDistanceInSeconds(absolutTime);
+ if (this.options.showNow && this.options.showNow > dis) {
+ return this.options.lang.prefixes.now;
+ } else if (this.options.maxRelative && this.options.maxRelative <= dis) {
+ return this.options.absoluteDate(absolutTime, timeString);
+ } else {
+ return "" + this.options.lang.prefixes.ago + (this.distanceOfTimeInWords(dis)) + (this.options.suffix || this.options.lang.suffix);
+ }
};
TimeAgo.prototype.parse = function(iso8601) {
var timeStr;
timeStr = $.trim(iso8601);
- timeStr = timeStr.replace(/\.\d\d\d+/, "");
+ timeStr = timeStr.replace(/\.\d+/, "");
timeStr = timeStr.replace(/-/, "/").replace(/-/, "/");
timeStr = timeStr.replace(/T/, " ").replace(/Z/, " UTC");
timeStr = timeStr.replace(/([\+\-]\d\d)\:?(\d\d)/, " $1$2");
return new Date(timeStr);
};
- TimeAgo.prototype.getTimeDistanceInMinutes = function(absolutTime) {
+ TimeAgo.prototype.getTimeDistanceInSeconds = function(absolutTime) {
var timeDistance;
timeDistance = new Date().getTime() - absolutTime.getTime();
- return Math.round((Math.abs(timeDistance) / 1000) / 60);
+ return Math.round(Math.abs(timeDistance) / 1000);
};
- TimeAgo.prototype.distanceOfTimeInWords = function(absolutTime) {
- var dim;
- dim = this.getTimeDistanceInMinutes(absolutTime);
- if (dim === 0) {
- return "" + this.options.lang.prefixes.lt + " " + this.options.lang.units.minute;
- } else if (dim === 1) {
- return "1 " + this.options.lang.units.minute;
- } else if (dim >= 2 && dim <= 44) {
- return "" + dim + " " + this.options.lang.units.minutes;
- } else if (dim >= 45 && dim <= 89) {
- return "" + this.options.lang.prefixes.about + " 1 " + this.options.lang.units.hour;
- } else if (dim >= 90 && dim <= 1439) {
- return "" + this.options.lang.prefixes.about + " " + (Math.round(dim / 60)) + " " + this.options.lang.units.hours;
- } else if (dim >= 1440 && dim <= 2519) {
- return "1 " + this.options.lang.units.day;
- } else if (dim >= 2520 && dim <= 43199) {
- return "" + (Math.round(dim / 1440)) + " " + this.options.lang.units.days;
- } else if (dim >= 43200 && dim <= 86399) {
- return "" + this.options.lang.prefixes.about + " 1 " + this.options.lang.units.month;
- } else if (dim >= 86400 && dim <= 525599) {
- return "" + (Math.round(dim / 43200)) + " " + this.options.lang.units.months;
- } else if (dim >= 525600 && dim <= 655199) {
- return "" + this.options.lang.prefixes.about + " 1 " + this.options.lang.units.year;
- } else if (dim >= 655200 && dim <= 914399) {
- return "" + this.options.lang.prefixes.over + " 1 " + this.options.lang.units.year;
- } else if (dim >= 914400 && dim <= 1051199) {
- return "" + this.options.lang.prefixes.almost + " 2 " + this.options.lang.units.years;
+ TimeAgo.prototype.distanceOfTimeInWords = function(dis) {
+ var space;
+ space = this.options.spacing ? ' ' : '';
+ if (dis < 60) {
+ if (this.options.showSeconds) {
+ if (dis === 0 || dis === 1) {
+ return "1" + space + this.options.lang.units.second;
+ } else {
+ return "" + dis + space + this.options.lang.units.seconds;
+ }
+ } else {
+ return "" + (this.options.approximate ? this.options.lang.prefixes.lt + " " : "1" + space) + this.options.lang.units.minute;
+ }
+ } else if (dis < 120) {
+ return "1" + space + this.options.lang.units.minute;
+ } else if (dis < 2700) {
+ return "" + (Math.round(dis / 60)) + space + this.options.lang.units.minutes;
+ } else if (dis < 5400) {
+ return "" + (this.options.approximate ? this.options.lang.prefixes.about + " " : "") + "1" + space + this.options.lang.units.hour;
+ } else if (dis < 86400) {
+ return "" + (this.options.approximate ? this.options.lang.prefixes.about + " " : "") + (Math.round(dis / 3600)) + space + this.options.lang.units.hours;
+ } else if (dis < 151200) {
+ return "1" + space + this.options.lang.units.day;
+ } else if (dis < 2592000) {
+ return "" + (Math.round(dis / 86400)) + space + this.options.lang.units.days;
+ } else if (dis < 5184000) {
+ return "" + (this.options.approximate ? this.options.lang.prefixes.about + " " : "") + "1" + space + this.options.lang.units.month;
+ } else if (dis < 31536000) {
+ return "" + (Math.round(dis / 2592000)) + space + this.options.lang.units.months;
+ } else if (dis < 39312000) {
+ return "" + (this.options.approximate ? this.options.lang.prefixes.about + " " : "") + "1" + space + this.options.lang.units.year;
+ } else if (dis < 54864000) {
+ return "" + (this.options.approximate ? this.options.lang.prefixes.over + " " : "") + "1" + space + this.options.lang.units.year;
+ } else if (dis < 63072000) {
+ return "" + (this.options.approximate ? this.options.lang.prefixes.almost + " " : "") + "2" + space + this.options.lang.units.years;
} else {
- return "" + this.options.lang.prefixes.about + " " + (Math.round(dim / 525600)) + " " + this.options.lang.units.years;
+ return "" + (this.options.approximate ? this.options.lang.prefixes.about + " " : "") + (Math.round(dis / 31536000)) + space + this.options.lang.units.years;
}
};
@@ -144,8 +142,12 @@
options = {};
}
return this.each(function() {
- var $this, data;
+ var $this, attr, data;
$this = $(this);
+ attr = $this.attr(options.attr || $.fn.timeago.defaults.attr);
+ if (attr === void 0 || attr === false) {
+ return;
+ }
data = $this.data("timeago");
if (!data) {
return $this.data("timeago", new TimeAgo(this, options));
@@ -162,9 +164,15 @@
$.fn.timeago.Constructor = TimeAgo;
$.fn.timeago.defaults = {
- selector: 'time.timeago',
attr: 'datetime',
- dir: 'up',
+ spacing: true,
+ approximate: true,
+ showSeconds: false,
+ showNow: false,
+ maxRelative: false,
+ absoluteDate: function(date, datetime) {
+ return datetime;
+ },
lang: {
units: {
second: "second",
@@ -181,6 +189,7 @@
years: "years"
},
prefixes: {
+ now: "just now",
lt: "less than a",
about: "about",
over: "over",
View
156 src/timeago.coffee
@@ -8,23 +8,17 @@
class TimeAgo
constructor: (element, options) ->
- @startInterval = 60000
- @init(element, options)
-
- init: (element, options) ->
@$element = $(element)
@options = $.extend({}, $.fn.timeago.defaults, options)
- @updateTime()
- @startTimer()
+ @refresh()
startTimer: ->
- self = @
- @interval = setInterval ( ->
- self.refresh()
- ), @startInterval
+ @interval = setTimeout(=>
+ @refresh()
+ , @startInterval)
stopTimer: ->
- clearInterval(@interval)
+ clearTimeout(@interval)
restartTimer: ->
@stopTimer()
@@ -35,37 +29,44 @@ class TimeAgo
@updateInterval()
updateTime: ->
- self = @
- @$element.findAndSelf(@options.selector).each ->
- timeAgoInWords = self.timeAgoInWords($(this).attr(self.options.attr))
- $(this).html(timeAgoInWords)
+ timeAgoInWords = @timeAgoInWords(@$element.attr(@options.attr))
+ @$element.html(timeAgoInWords)
updateInterval: ->
- if @$element.findAndSelf(@options.selector).length > 0
- if @options.dir is "up"
- filter = ":first"
- else if @options.dir is "down"
- filter = ":last"
- newestTimeSrc = @$element.findAndSelf(@options.selector).filter(filter).attr(@options.attr)
- newestTime = @parse(newestTimeSrc)
- newestTimeInMinutes = @getTimeDistanceInMinutes(newestTime)
-
- if newestTimeInMinutes >= 0 and newestTimeInMinutes <= 44 and @startInterval != 60000 #1 minute
- @startInterval = 60000
- @restartTimer()
- else if newestTimeInMinutes >= 45 and newestTimeInMinutes <= 89 and @startInterval != 60000 * 22 #22 minutes
- @startInterval = 60000 * 22
- @restartTimer()
- else if newestTimeInMinutes >= 90 and newestTimeInMinutes <= 2519 and @startInterval != 60000 * 30 #half hour
- @startInterval = 60000 * 30
- @restartTimer()
- else if newestTimeInMinutes >= 2520 and @startInterval != 60000 * 60 * 12 #half day
- @startInterval = 60000 * 60 * 12
- @restartTimer()
+ newestTimeSrc = @$element.attr(@options.attr)
+ newestTime = @parse(newestTimeSrc)
+ dis = @getTimeDistanceInSeconds(newestTime)
+
+ if @options.maxRelative and dis >= @options.maxRelative
+ @stopTimer()
+ else if @options.showNow and dis < @options.showNow
+ @startInterval = (@options.showNow - dis) * 1000
+ @restartTimer()
+ else if @options.showSeconds and dis < 60
+ @startInterval = 1000
+ @restartTimer()
+ else if dis < 2700
+ @startInterval = (60 - dis % 60) * 1000
+ @restartTimer()
+ else if dis < 5400
+ @startInterval = (5400 - dis) * 1000
+ @restartTimer()
+ else if dis < 151200
+ @startInterval = (3600 - dis % 3600) * 1000
+ @restartTimer()
+ else
+ @startInterval = (86400 - dis % 86400) * 1000
+ @restartTimer()
timeAgoInWords: (timeString) ->
absolutTime = @parse(timeString)
- "#{@options.lang.prefixes.ago}#{@distanceOfTimeInWords(absolutTime)}#{@options.lang.suffix}"
+ dis = @getTimeDistanceInSeconds(absolutTime) #distance in seconds
+ if @options.showNow and @options.showNow > dis
+ @options.lang.prefixes.now
+ else if @options.maxRelative and @options.maxRelative <= dis
+ @options.absoluteDate(absolutTime, timeString)
+ else
+ "#{@options.lang.prefixes.ago}#{@distanceOfTimeInWords(dis)}#{@options.suffix or @options.lang.suffix}"
parse: (iso8601) ->
timeStr = $.trim(iso8601)
@@ -73,46 +74,56 @@ class TimeAgo
timeStr = timeStr.replace(/-/,"/").replace(/-/,"/")
timeStr = timeStr.replace(/T/," ").replace(/Z/," UTC")
timeStr = timeStr.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2")
- new Date(timeStr);
+ new Date(timeStr)
- getTimeDistanceInMinutes: (absolutTime) ->
+ getTimeDistanceInSeconds: (absolutTime) ->
timeDistance = new Date().getTime() - absolutTime.getTime()
- Math.round((Math.abs(timeDistance) / 1000) / 60)
+ Math.round(Math.abs(timeDistance) / 1000)
- distanceOfTimeInWords: (absolutTime) ->
+ distanceOfTimeInWords: (dis) ->
#TODO support i18n.
- dim = @getTimeDistanceInMinutes(absolutTime) #distance in minutes
-
- if dim == 0
- "#{ @options.lang.prefixes.lt } #{ @options.lang.units.minute }"
- else if dim == 1
- "1 #{ @options.lang.units.minute }"
- else if dim >= 2 and dim <= 44
- "#{ dim } #{ @options.lang.units.minutes }"
- else if dim >= 45 and dim <= 89
- "#{ @options.lang.prefixes.about } 1 #{ @options.lang.units.hour }"
- else if dim >= 90 and dim <= 1439
- "#{ @options.lang.prefixes.about } #{ Math.round(dim / 60) } #{ @options.lang.units.hours }"
- else if dim >= 1440 and dim <= 2519
- "1 #{ @options.lang.units.day }"
- else if dim >= 2520 and dim <= 43199
- "#{ Math.round(dim / 1440) } #{ @options.lang.units.days }"
- else if dim >= 43200 and dim <= 86399
- "#{ @options.lang.prefixes.about } 1 #{ @options.lang.units.month }"
- else if dim >= 86400 and dim <= 525599 #1 yr
- "#{ Math.round(dim / 43200) } #{ @options.lang.units.months }"
- else if dim >= 525600 and dim <= 655199 #1 yr, 3 months
- "#{ @options.lang.prefixes.about } 1 #{ @options.lang.units.year }"
- else if dim >= 655200 and dim <= 914399 #1 yr, 9 months
- "#{ @options.lang.prefixes.over } 1 #{ @options.lang.units.year }"
- else if dim >= 914400 and dim <= 1051199 #2 yr minus half minute
- "#{ @options.lang.prefixes.almost } 2 #{ @options.lang.units.years }"
+ space = if @options.spacing then ' ' else ''
+
+ if dis < 60
+ if @options.showSeconds
+ if dis == 0 or dis == 1
+ "1#{ space }#{ @options.lang.units.second }"
+ else
+ "#{ dis }#{ space }#{ @options.lang.units.seconds }"
+ else
+ "#{ if @options.approximate then @options.lang.prefixes.lt + " " else "1" + space }#{ @options.lang.units.minute }"
+ else if dis < 120
+ "1#{ space }#{ @options.lang.units.minute }"
+ else if dis < 2700
+ "#{ Math.round(dis / 60) }#{ space }#{ @options.lang.units.minutes }"
+ else if dis < 5400
+ "#{ if @options.approximate then @options.lang.prefixes.about + " " else "" }1#{ space }#{ @options.lang.units.hour }"
+ else if dis < 86400
+ "#{ if @options.approximate then @options.lang.prefixes.about + " " else "" }#{ Math.round(dis / 3600) }#{ space }#{ @options.lang.units.hours }"
+ else if dis < 151200
+ "1#{ space }#{ @options.lang.units.day }"
+ else if dis < 2592000
+ "#{ Math.round(dis / 86400) }#{ space }#{ @options.lang.units.days }"
+ else if dis < 5184000
+ "#{ if @options.approximate then @options.lang.prefixes.about + " " else "" }1#{ space }#{ @options.lang.units.month }"
+ else if dis < 31536000 #1 yr
+ "#{ Math.round(dis / 2592000) }#{ space }#{ @options.lang.units.months }"
+ else if dis < 39312000 #1 yr, 3 months
+ "#{ if @options.approximate then @options.lang.prefixes.about + " " else "" }1#{ space }#{ @options.lang.units.year }"
+ else if dis < 54864000 #1 yr, 9 months
+ "#{ if @options.approximate then @options.lang.prefixes.over + " " else "" }1#{ space }#{ @options.lang.units.year }"
+ else if dis < 63072000 #2 yr minus half minute
+ "#{ if @options.approximate then @options.lang.prefixes.almost + " " else "" }2#{ space }#{ @options.lang.units.years }"
else
- "#{ @options.lang.prefixes.about } #{ Math.round(dim / 525600) } #{ @options.lang.units.years }"
+ "#{ if @options.approximate then @options.lang.prefixes.about + " " else "" }#{ Math.round(dis / 31536000) }#{ space }#{ @options.lang.units.years }"
$.fn.timeago = (options = {}) ->
@each ->
$this = $(this)
+ attr = $this.attr(options.attr or $.fn.timeago.defaults.attr)
+ if attr == undefined or attr == false
+ return
+
data = $this.data("timeago")
if (!data)
$this.data("timeago", new TimeAgo(this, options))
@@ -125,9 +136,13 @@ $.fn.findAndSelf = (selector) ->
$.fn.timeago.Constructor = TimeAgo
$.fn.timeago.defaults =
- selector: 'time.timeago'
attr: 'datetime'
- dir: 'up'
+ spacing: true
+ approximate: true
+ showSeconds: false
+ showNow: false
+ maxRelative: false
+ absoluteDate: (date, datetime) -> datetime
lang:
units:
second: "second"
@@ -143,6 +158,7 @@ $.fn.timeago.defaults =
year: "year"
years: "years"
prefixes:
+ now: "just now"
lt: "less than a"
about: "about"
over: "over"
View
1  test/index.html
@@ -15,6 +15,7 @@
<script src="specs/timeago_spec.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
+ <time class="timeago" datetime="2012-07-18T07:51:50Z" style="display:none"></time>
<script type="text/javascript">
(function() {
View
365 test/specs/timeago_spec.js
@@ -11,46 +11,15 @@ describe("TimeAgo", function(){
timeAgo = new TimeAgo("time.timeago", {})
});
- describe("constructor", function(){
- it("should contain the startInterval", function(){
- expect(timeAgo.startInterval).toEqual(60000);
- });
- });
-
- describe("#init", function(){
- it("should set $element", function(){
- timeAgo.init("time.timeago", {});
- expect(timeAgo.$element).toEqual($("time.timeago"));
- });
-
- it("should load the options", function(){
- spyOn($, 'extend').andReturn("spy");
- timeAgo.init("time.timeago", {});
- expect(timeAgo.options).toEqual("spy");
- });
-
- it("should call updateTime", function(){
- spyOn(timeAgo, 'updateTime');
- timeAgo.init("time.timeago", {});
- expect(timeAgo.updateTime).toHaveBeenCalled();
- });
-
- it("should call startTimer", function(){
- spyOn(timeAgo, "startTimer");
- timeAgo.init("time.time", {});
- expect(timeAgo.startTimer).toHaveBeenCalled();
- });
- });
-
describe("#startTimer", function(){
it("should call setInterval", function(){
- spyOn(window, 'setInterval');
+ spyOn(window, 'setTimeout');
timeAgo.startTimer();
- expect(window.setInterval).toHaveBeenCalled();
+ expect(window.setTimeout).toHaveBeenCalled();
});
it("should set interval", function(){
- spyOn(window, 'setInterval').andReturn("spy");
+ spyOn(window, 'setTimeout').andReturn("spy");
timeAgo.startTimer();
expect(timeAgo.interval).toEqual("spy");
});
@@ -58,9 +27,9 @@ describe("TimeAgo", function(){
describe("#stopTimer",function(){
it("should call clearInterval", function(){
- spyOn(window, 'clearInterval');
+ spyOn(window, 'clearTimeout');
timeAgo.stopTimer();
- expect(window.clearInterval).toHaveBeenCalled();
+ expect(window.clearTimeout).toHaveBeenCalled();
});
});
@@ -82,7 +51,7 @@ describe("TimeAgo", function(){
beforeEach(function(){
timeLabel = $('<time class="timeago" datetime="2012-07-18T07:51:50Z">about 8 hours ago</time>')
$('body').append(timeLabel)
- timeAgo = new TimeAgo("time.timeago", {selector: 'time.timeago', attr: 'datetime', dir: 'up', suffix: 'ago'});
+ timeAgo = new TimeAgo("time.timeago", { attr: 'datetime', suffix: 'ago'});
});
afterEach(function(){
@@ -100,7 +69,7 @@ describe("TimeAgo", function(){
beforeEach(function(){
timeLabel = $('<time class="timeago" datetime="2012-07-18T07:51:50Z">about 8 hours ago</time>')
$('body').append(timeLabel)
- timeAgo = new TimeAgo("time.timeago", {selector: 'time.timeago', attr: 'datetime', dir: 'up', suffix: 'ago'});
+ timeAgo = new TimeAgo("time.timeago", { attr: 'datetime', suffix: 'ago'});
});
afterEach(function(){
@@ -108,76 +77,76 @@ describe("TimeAgo", function(){
});
- describe("context: newestTimeInMinutes >= 0 and newestTimeInMinutes <= 45 and @startInterval != 60000", function(){
+ describe("context: newestTimeInSeconds >= 0 and newestTimeInSeconds < 2700 and @startInterval != 60000", function(){
beforeEach(function(){
timeAgo.startInterval = 60000 * 22;
});
it("should update interval to 60000", function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(2);
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(120);
timeAgo.updateInterval();
expect(timeAgo.startInterval).toEqual(60000);
});
it("should call restartTimer", function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(2);
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(120);
spyOn(timeAgo, 'restartTimer');
timeAgo.updateInterval();
expect(timeAgo.restartTimer).toHaveBeenCalled();
});
});
- describe("context: newestTimeInMinutes >= 45 and newestTimeInMinutes <= 89 and @startInterval != 60000 * 30", function(){
+ describe("context: newestTimeInSeconds >= 2700 and newestTimeInSeconds < 5400 and @startInterval != 60000 * 30", function(){
beforeEach(function(){
timeAgo.startInterval = 60000;
});
- it("should update interval to 1320000", function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(46);
+ it("should update interval to (5400 - dis) * 1000", function(){
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(2760);
timeAgo.updateInterval();
- expect(timeAgo.startInterval).toEqual(1320000);
+ expect(timeAgo.startInterval).toEqual((5400 - 2760) * 1000);
});
it("should call restartTimer", function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(46);
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(2760);
spyOn(timeAgo, 'restartTimer');
timeAgo.updateInterval();
expect(timeAgo.restartTimer).toHaveBeenCalled();
});
});
- describe("context: newestTimeInMinutes >= 90 and newestTimeInMinutes <= 2519 and @startInterval != 60000 * 60", function(){
+ describe("context: newestTimeInSeconds >= 5400 and newestTimeInSeconds < 151200 and @startInterval != 60000 * 60", function(){
beforeEach(function(){
timeAgo.startInterval = 1320000;
});
it("should update interval to 1800000", function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(90);
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(5400);
timeAgo.updateInterval();
expect(timeAgo.startInterval).toEqual(1800000);
});
it("should call restartTimer", function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(2519);
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(151100);
spyOn(timeAgo, 'restartTimer');
timeAgo.updateInterval();
expect(timeAgo.restartTimer).toHaveBeenCalled();
});
});
- describe("context: newestTimeInMinutes >= 2520 and @startInterval != 60000 * 60 * 24", function(){
+ describe("context: newestTimeInSeconds >= 151200 and @startInterval != 60000 * 60 * 24", function(){
beforeEach(function(){
timeAgo.startInterval = 1800000;
});
- it("should update interval to 43200000", function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(2520);
+ it("should update interval to (86400 - dis % 86400) * 1000", function(){
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(151200);
timeAgo.updateInterval();
- expect(timeAgo.startInterval).toEqual(43200000);
+ expect(timeAgo.startInterval).toEqual((86400 - 151200 % 86400) * 1000);
});
it("should call restartTimer", function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(100000000);
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(6000000000);
spyOn(timeAgo, 'restartTimer');
timeAgo.updateInterval();
expect(timeAgo.restartTimer).toHaveBeenCalled();
@@ -200,120 +169,290 @@ describe("TimeAgo", function(){
describe("distanceOfTimeInWords", function(){
- describe("context: dim == 0", function(){
- beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(0);
- });
+ describe("context: dis == 0", function(){
it("should return 'less than a minute'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("less than a minute");
+ expect(timeAgo.distanceOfTimeInWords(0)).toEqual("less than a minute");
});
});
- describe("context: dim == 1", function(){
- beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(1);
- });
+ describe("context: dis == 60", function(){
it("should return '1 minute'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("1 minute");
+ expect(timeAgo.distanceOfTimeInWords(60)).toEqual("1 minute");
});
});
- describe("context: dim >= 2 and dim <= 44", function(){
- beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(2);
- });
+ describe("context: dis >= 120 and dim < 2700", function(){
it("should return '2 minutes'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("2 minutes");
+ expect(timeAgo.distanceOfTimeInWords(120)).toEqual("2 minutes");
});
});
- describe("context: dim >= 45 and dim <= 89", function(){
- beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(89);
- });
+ describe("context: dis >= 2700 and dim < 5400", function(){
it("should return 'about 1 hour'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("about 1 hour");
+ expect(timeAgo.distanceOfTimeInWords(5300)).toEqual("about 1 hour");
});
});
- describe("context: dim >= 90 and dim <= 1439", function(){
- beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(120);
- });
+ describe("context: dis >= 5400 and dim < 86400", function(){
it("should return 'about 2 hours'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("about 2 hours");
+ expect(timeAgo.distanceOfTimeInWords(7200)).toEqual("about 2 hours");
});
});
- describe("context: dim >= 1440 and dim <= 2519", function(){
- beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(2519);
- });
+ describe("context: dis >= 86400 and dim < 151200", function(){
it("should return '1 day'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("1 day");
+ expect(timeAgo.distanceOfTimeInWords(151100)).toEqual("1 day");
});
});
- describe("context: dim >= 2520 and dim <= 43199", function(){
- beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(2520);
- });
+ describe("context: dis >= 151200 and dim < 2592000", function(){
it("should return '2 days'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("2 days");
+ expect(timeAgo.distanceOfTimeInWords(151200)).toEqual("2 days");
+ });
+ });
+
+ describe("context: dis >= 2592000 and dim < 5184000", function(){
+ it("should return 'about 1 month'", function(){
+ expect(timeAgo.distanceOfTimeInWords(5183000)).toEqual("about 1 month");
+ });
+ });
+
+ describe("context: dis >= 5184000 and dim < 31536000", function(){
+ it("should return '12 months'", function(){
+ expect(timeAgo.distanceOfTimeInWords(31535940)).toEqual("12 months");
});
});
- describe("context: dim >= 43200 and dim <= 86399", function(){
+ describe("context: dis >= 31536000 and dim < 39312000", function(){
+ it("should return 'about 1 year'", function(){
+ expect(timeAgo.distanceOfTimeInWords(31536000)).toEqual("about 1 year");
+ });
+ });
+
+ describe("context: dis >= 39312000 and dim < 54864000", function(){
+ it("should return 'over 1 year'", function(){
+ expect(timeAgo.distanceOfTimeInWords(39312000)).toEqual("over 1 year");
+ });
+ });
+
+ describe("context: dis >= 54864000 and dim < 63072000", function(){
+ it("should return 'almost 2 years'", function(){
+ expect(timeAgo.distanceOfTimeInWords(54864000)).toEqual("almost 2 years");
+ });
+ });
+
+ describe("context: dis >= 63072000", function(){
+ it("should return 'about 2 years'", function(){
+ expect(timeAgo.distanceOfTimeInWords(63072000)).toEqual("about 2 years");
+ });
+ });
+
+ });
+
+ describe("options", function(){
+ describe("spacing == false", function(){
beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(86399);
+ timeAgo.options.spacing = false;
});
- it("should return 'about 1 month'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("about 1 month");
+ it("should return '1minute'", function() {
+ expect(timeAgo.distanceOfTimeInWords(60)).toEqual("1minute");
+ });
+ afterEach(function(){
+ timeAgo.options.spacing = true;
});
});
- describe("context: dim >= 86400 and dim <= 525599", function(){
+ describe("approximate == false", function(){
beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(525599);
+ timeAgo.options.approximate = false;
});
- it("should return '12 months'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("12 months");
+
+ describe("context: dis == 0", function(){
+ it("should return '1 minute'", function(){
+ expect(timeAgo.distanceOfTimeInWords(0)).toEqual("1 minute");
+ });
+ });
+
+ describe("context: dis == 60", function(){
+ it("should return '1 minute'", function(){
+ expect(timeAgo.distanceOfTimeInWords(60)).toEqual("1 minute");
+ });
+ });
+
+ describe("context: dis >= 120 and dim < 2700", function(){
+ it("should return '2 minutes'", function(){
+ expect(timeAgo.distanceOfTimeInWords(120)).toEqual("2 minutes");
+ });
+ });
+
+ describe("context: dis >= 2700 and dim < 5400", function(){
+ it("should return '1 hour'", function(){
+ expect(timeAgo.distanceOfTimeInWords(5300)).toEqual("1 hour");
+ });
+ });
+
+ describe("context: dis >= 5400 and dim < 86400", function(){
+ it("should return '2 hours'", function(){
+ expect(timeAgo.distanceOfTimeInWords(7200)).toEqual("2 hours");
+ });
+ });
+
+ describe("context: dis >= 86400 and dim < 151200", function(){
+ it("should return '1 day'", function(){
+ expect(timeAgo.distanceOfTimeInWords(151100)).toEqual("1 day");
+ });
+ });
+
+ describe("context: dis >= 151200 and dim < 2592000", function(){
+ it("should return '2 days'", function(){
+ expect(timeAgo.distanceOfTimeInWords(151200)).toEqual("2 days");
+ });
+ });
+
+ describe("context: dis >= 2592000 and dim < 5184000", function(){
+ it("should return '1 month'", function(){
+ expect(timeAgo.distanceOfTimeInWords(5183000)).toEqual("1 month");
+ });
+ });
+
+ describe("context: dis >= 5184000 and dim < 31536000", function(){
+ it("should return '12 months'", function(){
+ expect(timeAgo.distanceOfTimeInWords(31535940)).toEqual("12 months");
+ });
+ });
+
+ describe("context: dis >= 31536000 and dim < 39312000", function(){
+ it("should return '1 year'", function(){
+ expect(timeAgo.distanceOfTimeInWords(31536000)).toEqual("1 year");
+ });
+ });
+
+ describe("context: dis >= 39312000 and dim < 54864000", function(){
+ it("should return '1 year'", function(){
+ expect(timeAgo.distanceOfTimeInWords(39312000)).toEqual("1 year");
+ });
+ });
+
+ describe("context: dis >= 54864000 and dim < 63072000", function(){
+ it("should return '2 years'", function(){
+ expect(timeAgo.distanceOfTimeInWords(54864000)).toEqual("2 years");
+ });
+ });
+
+ describe("context: dis >= 63072000", function(){
+ it("should return '2 years'", function(){
+ expect(timeAgo.distanceOfTimeInWords(63072000)).toEqual("2 years");
+ });
+ });
+
+ afterEach(function(){
+ timeAgo.options.approximate = true;
});
});
- describe("context: dim >= 525600 and dim <= 655199", function(){
+ describe("suffix == ' from now'", function(){
beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(525600);
+ timeAgo.options.suffix = ' from now';
});
- it("should return 'about 1 year'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("about 1 year");
+
+ describe("context: dis >= 63072000", function(){
+ beforeEach(function(){
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(63072000);
+ });
+ it("should return 'about 2 years from now'", function(){
+ expect(timeAgo.timeAgoInWords(new Date().toString())).toEqual("about 2 years from now");
+ });
+ });
+
+ afterEach(function(){
+ timeAgo.options.suffix = ' ago';
});
});
- describe("context: dim >= 655200 and dim <= 914399", function(){
+ describe("showSeconds == true", function(){
beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(655200);
+ timeAgo.options.showSeconds = true;
});
- it("should return 'over 1 year'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("over 1 year");
+
+ describe("context: dis == 0", function(){
+ it("should return '1 second'", function(){
+ expect(timeAgo.distanceOfTimeInWords(0)).toEqual("1 second");
+ });
+ });
+
+ describe("context: dis == 1", function(){
+ it("should return '1 second'", function(){
+ expect(timeAgo.distanceOfTimeInWords(1)).toEqual("1 second");
+ });
+ });
+
+ describe("context: dis == 30", function(){
+ it("should return '30 seconds'", function(){
+ expect(timeAgo.distanceOfTimeInWords(30)).toEqual("30 seconds");
+ });
+ });
+
+ afterEach(function(){
+ timeAgo.options.showSeconds = false;
});
});
- describe("context: dim >= 914400 and dim <= 1051199", function(){
+ describe("showSeconds == true and showNow == 5", function(){
beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(914400);
+ timeAgo.options.showSeconds = true;
+ timeAgo.options.showNow = 15;
});
- it("should return 'almost 2 years'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("almost 2 years");
+
+ describe("context: dis == 5", function(){
+ beforeEach(function(){
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(5);
+ });
+ it("should return 'just now'", function(){
+ expect(timeAgo.timeAgoInWords(new Date().toString())).toEqual("just now");
+ });
+ });
+
+ describe("context: dis == 20", function(){
+ beforeEach(function(){
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(20);
+ });
+ it("should return '20 seconds ago'", function(){
+ expect(timeAgo.timeAgoInWords(new Date().toString())).toEqual("20 seconds ago");
+ });
+ });
+
+ afterEach(function(){
+ timeAgo.options.showSeconds = false;
+ timeAgo.options.showNow = false;
});
});
- describe("context: >= 1051200", function(){
+ describe("maxRelative == 2592000", function(){
beforeEach(function(){
- spyOn(timeAgo, 'getTimeDistanceInMinutes').andReturn(1051200);
+ timeAgo.options.maxRelative = 2592000;
});
- it("should return 'almost 2 years'", function(){
- expect(timeAgo.distanceOfTimeInWords(new Date())).toEqual("about 2 years");
+
+ describe("context: dis == 5", function(){
+ beforeEach(function(){
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(5);
+ });
+ it("should return 'less than a minute ago'", function(){
+ expect(timeAgo.timeAgoInWords(new Date().toString())).toEqual("less than a minute ago");
+ });
+ });
+
+ describe("context: dis == 2600000", function(){
+ beforeEach(function(){
+ spyOn(timeAgo, 'getTimeDistanceInSeconds').andReturn(2600000);
+ });
+ var datetime = '2012-07-18T07:51:50Z';
+ it("should return '" + datetime + "'", function(){
+ expect(timeAgo.timeAgoInWords(datetime)).toEqual(datetime);
+ });
+ });
+
+ afterEach(function(){
+ timeAgo.options.maxRelative = false;
});
});
Something went wrong with that request. Please try again.