// default relative time thresholds
relativeTimeThresholds = {
- s: 45, //seconds to minutes
- m: 45, //minutes to hours
- h: 22, //hours to days
- dd: 25, //days to month (month == 1)
- dm: 45, //days to months (months > 1)
- dy: 345 //days to year
+ s: 45, // seconds to minute
+ m: 45, // minutes to hour
+ h: 22, // hours to day
+ d: 26, // days to month
+ M: 11 // months to year
},
// tokens to ordinalize and pad
y : "a year",
yy : "%d years"
},
+
relativeTime : function (number, withoutSuffix, string, isFuture) {
var output = this._relativeTime[string];
return (typeof output === 'function') ?
output(number, withoutSuffix, string, isFuture) :
output.replace(/%d/i, number);
},
+
pastFuture : function (diff, output) {
var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
}
- function relativeTime(milliseconds, withoutSuffix, lang) {
- var seconds = round(Math.abs(milliseconds) / 1000),
- minutes = round(seconds / 60),
- hours = round(minutes / 60),
- days = round(hours / 24),
- years = round(days / 365),
- args = seconds < relativeTimeThresholds.s && ['s', seconds] ||
+ function relativeTime(msOrDuration, withoutSuffix, lang) {
+ var duration = (typeof msOrDuration === "number" ?
+ moment.duration(Math.abs(msOrDuration)) :
+ moment.duration(msOrDuration).abs()),
+ seconds = round(duration.as('s')),
+ minutes = round(duration.as('m')),
+ hours = round(duration.as('h')),
+ days = round(duration.as('d')),
+ months = round(duration.as('M')),
+ years = round(duration.as('y')),
+
+ args = seconds < relativeTimeThresholds.s && ['s', seconds] ||
minutes === 1 && ['m'] ||
minutes < relativeTimeThresholds.m && ['mm', minutes] ||
hours === 1 && ['h'] ||
hours < relativeTimeThresholds.h && ['hh', hours] ||
days === 1 && ['d'] ||
- days <= relativeTimeThresholds.dd && ['dd', days] ||
- days <= relativeTimeThresholds.dm && ['M'] ||
- days < relativeTimeThresholds.dy && ['MM', round(days / 30)] ||
+ days < relativeTimeThresholds.d && ['dd', days] ||
+ months === 1 && ['M'] ||
+ months < relativeTimeThresholds.M && ['MM', months] ||
years === 1 && ['y'] || ['yy', years];
+
args[2] = withoutSuffix;
- args[3] = milliseconds > 0;
+ args[3] = +msOrDuration > 0;
args[4] = lang;
return substituteTimeAgo.apply({}, args);
}
},
from : function (time, withoutSuffix) {
- return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix);
+ return moment.duration({to: this, from: time}).lang(this.lang()._abbr).humanize(!withoutSuffix);
},
fromNow : function (withoutSuffix) {
************************************/
+ function daysToYears (days) {
+ // 400 years have 146097 days (taking into account leap year rules)
+ return days * 400 / 146097;
+ }
+
+ function yearsToDays (years) {
+ // years * 365 + absRound(years / 4) -
+ // absRound(years / 100) + absRound(years / 400);
+ return years * 146097 / 400;
+ }
+
extend(moment.duration.fn = Duration.prototype, {
_bubble : function () {
days += absRound(hours / 24);
// Accurately convert days to years, assume start from year 0.
- years = absRound(days * 400 / 146097);
- days -= years * 365 + absRound(years / 4) -
- absRound(years / 100) + absRound(years / 400);
+ years = absRound(daysToYears(days));
+ days -= absRound(yearsToDays(years));
// 30 days to a month
// TODO (iskren): Use anchor date (like 1st Jan) to compute this.
data.years = years;
},
+ abs : function () {
+ this._milliseconds = Math.abs(this._milliseconds);
+ this._days = Math.abs(this._days);
+ this._months = Math.abs(this._months);
+
+ this._data.milliseconds = Math.abs(this._data.milliseconds);
+ this._data.seconds = Math.abs(this._data.seconds);
+ this._data.minutes = Math.abs(this._data.minutes);
+ this._data.hours = Math.abs(this._data.hours);
+ this._data.months = Math.abs(this._data.months);
+ this._data.years = Math.abs(this._data.years);
+
+ return this;
+ },
+
weeks : function () {
return absRound(this.days() / 7);
},
},
humanize : function (withSuffix) {
- var difference = +this,
- output = relativeTime(difference, !withSuffix, this.lang());
+ var output = relativeTime(this, !withSuffix, this.lang());
if (withSuffix) {
- output = this.lang().pastFuture(difference, output);
+ output = this.lang().pastFuture(+this, output);
}
return this.lang().postformat(output);
},
as : function (units) {
+ var days, months;
units = normalizeUnits(units);
- return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's']();
+
+ days = this._days + this._milliseconds / 864e5;
+ if (units === 'month' || units === 'year') {
+ months = this._months + daysToYears(days) * 12;
+ return units === 'month' ? months : months / 12;
+ } else {
+ days += yearsToDays(this._months / 12);
+ switch (units) {
+ case 'week': return days / 7;
+ case 'day': return days;
+ case 'hour': return days * 24;
+ case 'minute': return days * 24 * 60;
+ case 'second': return days * 24 * 60 * 60;
+ case 'millisecond': return days * 24 * 60 * 60 * 1000;
+ default: throw new Error("Unknown unit " + units);
+ }
+ }
},
lang : moment.fn.lang,
};
}
- function makeDurationAsGetter(name, factor) {
- moment.duration.fn['as' + name] = function () {
- return +this / factor;
- };
- }
-
for (i in unitMillisecondFactors) {
if (unitMillisecondFactors.hasOwnProperty(i)) {
- makeDurationAsGetter(i, unitMillisecondFactors[i]);
makeDurationGetter(i.toLowerCase());
}
}
- makeDurationAsGetter('Weeks', 6048e5);
- moment.duration.fn.asMonths = function () {
- return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12;
- };
-
+ moment.duration.fn.asMilliseconds = function () { return this.as('ms'); };
+ moment.duration.fn.asSeconds = function () { return this.as('s'); };
+ moment.duration.fn.asMinutes = function () { return this.as('m'); };
+ moment.duration.fn.asHours = function () { return this.as('h'); };
+ moment.duration.fn.asDays = function () { return this.as('d'); };
+ moment.duration.fn.asWeeks = function () { return this.as('weeks'); };
+ moment.duration.fn.asMonths = function () { return this.as('M'); };
+ moment.duration.fn.asYears = function () { return this.as('Y'); };
/************************************
Default Lang
test.done();
},
+ "from relative time future" : function (test) {
+ var start = moment([2007, 1, 28]);
+
+ test.equal(start.from(moment([2007, 1, 28]).subtract({s: 44})), "in a few seconds", "44 seconds = a few seconds");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({s: 45})), "in a minute", "45 seconds = a minute");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({s: 89})), "in a minute", "89 seconds = a minute");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({s: 90})), "in 2 minutes", "90 seconds = 2 minutes");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({m: 44})), "in 44 minutes", "44 minutes = 44 minutes");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({m: 45})), "in an hour", "45 minutes = an hour");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({m: 89})), "in an hour", "89 minutes = an hour");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({m: 90})), "in 2 hours", "90 minutes = 2 hours");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({h: 5})), "in 5 hours", "5 hours = 5 hours");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({h: 21})), "in 21 hours", "21 hours = 21 hours");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({h: 22})), "in a day", "22 hours = a day");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({h: 35})), "in a day", "35 hours = a day");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({h: 36})), "in 2 days", "36 hours = 2 days");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 1})), "in a day", "1 day = a day");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 5})), "in 5 days", "5 days = 5 days");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 25})), "in 25 days", "25 days = 25 days");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 26})), "in a month", "26 days = a month");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 30})), "in a month", "30 days = a month");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 45})), "in a month", "45 days = a month");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 46})), "in 2 months", "46 days = 2 months");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 74})), "in 2 months", "75 days = 2 months");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 76})), "in 3 months", "76 days = 3 months");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({M: 1})), "in a month", "1 month = a month");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({M: 5})), "in 5 months", "5 months = 5 months");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 344})), "in 11 months", "344 days = 11 months");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 345})), "in a year", "345 days = a year");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 547})), "in a year", "547 days = a year");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({d: 548})), "in a year", "548 days = a year");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({y: 1})), "in a year", "1 year = a year");
+ test.equal(start.from(moment([2007, 1, 28]).subtract({y: 5})), "in 5 years", "5 years = 5 years");
+
+ test.done();
+ },
+
+ "from relative time past" : function (test) {
+ var start = moment([2007, 1, 28]);
+
+ test.equal(start.from(moment([2007, 1, 28]).add({s: 44})), "a few seconds ago", "44 seconds = a few seconds");
+ test.equal(start.from(moment([2007, 1, 28]).add({s: 45})), "a minute ago", "45 seconds = a minute");
+ test.equal(start.from(moment([2007, 1, 28]).add({s: 89})), "a minute ago", "89 seconds = a minute");
+ test.equal(start.from(moment([2007, 1, 28]).add({s: 90})), "2 minutes ago", "90 seconds = 2 minutes");
+ test.equal(start.from(moment([2007, 1, 28]).add({m: 44})), "44 minutes ago", "44 minutes = 44 minutes");
+ test.equal(start.from(moment([2007, 1, 28]).add({m: 45})), "an hour ago", "45 minutes = an hour");
+ test.equal(start.from(moment([2007, 1, 28]).add({m: 89})), "an hour ago", "89 minutes = an hour");
+ test.equal(start.from(moment([2007, 1, 28]).add({m: 90})), "2 hours ago", "90 minutes = 2 hours");
+ test.equal(start.from(moment([2007, 1, 28]).add({h: 5})), "5 hours ago", "5 hours = 5 hours");
+ test.equal(start.from(moment([2007, 1, 28]).add({h: 21})), "21 hours ago", "21 hours = 21 hours");
+ test.equal(start.from(moment([2007, 1, 28]).add({h: 22})), "a day ago", "22 hours = a day");
+ test.equal(start.from(moment([2007, 1, 28]).add({h: 35})), "a day ago", "35 hours = a day");
+ test.equal(start.from(moment([2007, 1, 28]).add({h: 36})), "2 days ago", "36 hours = 2 days");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 1})), "a day ago", "1 day = a day");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 5})), "5 days ago", "5 days = 5 days");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 25})), "25 days ago", "25 days = 25 days");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 26})), "a month ago", "26 days = a month");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 30})), "a month ago", "30 days = a month");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 45})), "2 months ago", "45 days = 2 months");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 46})), "2 months ago", "46 days = 2 months");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 74})), "2 months ago", "75 days = 2 months");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 76})), "3 months ago", "76 days = 3 months");
+ test.equal(start.from(moment([2007, 1, 28]).add({M: 1})), "a month ago", "1 month = a month");
+ test.equal(start.from(moment([2007, 1, 28]).add({M: 5})), "5 months ago", "5 months = 5 months");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 344})), "11 months ago", "344 days = 11 months");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 345})), "a year ago", "345 days = a year");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 547})), "a year ago", "547 days = a year");
+ test.equal(start.from(moment([2007, 1, 28]).add({d: 548})), "a year ago", "548 days = a year");
+ test.equal(start.from(moment([2007, 1, 28]).add({y: 1})), "a year ago", "1 year = a year");
+ test.equal(start.from(moment([2007, 1, 28]).add({y: 5})), "5 years ago", "5 years = 5 years");
+
+ test.done();
+ },
+
"instance lang used with from" : function (test) {
test.expect(2);
moment.lang('en');