From: Iskren Chernev Date: Sun, 27 Apr 2014 20:09:49 +0000 (-0700) Subject: Use duration object in relativeTime X-Git-Tag: 2.8.0~29^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=af40f1dc864279850f503d4cee24c846f4b9d21b;p=thirdparty%2Fmoment.git Use duration object in relativeTime --- diff --git a/moment.js b/moment.js index ff6641d39..2d72b5424 100644 --- a/moment.js +++ b/moment.js @@ -147,12 +147,11 @@ // 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 @@ -830,12 +829,14 @@ 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); @@ -1597,24 +1598,30 @@ 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); } @@ -2106,7 +2113,7 @@ }, 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) { @@ -2444,6 +2451,17 @@ ************************************/ + 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 () { @@ -2469,9 +2487,8 @@ 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. @@ -2487,6 +2504,21 @@ 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); }, @@ -2499,11 +2531,10 @@ }, 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); @@ -2540,8 +2571,25 @@ }, 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, @@ -2579,24 +2627,20 @@ }; } - 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 diff --git a/test/moment/duration.js b/test/moment/duration.js index 39673d8d5..a37ee2c57 100644 --- a/test/moment/duration.js +++ b/test/moment/duration.js @@ -357,13 +357,13 @@ exports.duration = { test.equal(moment.duration({days: 25}).humanize(), "25 days", "25 days = 25 days"); test.equal(moment.duration({days: 26}).humanize(), "a month", "26 days = a month"); test.equal(moment.duration({days: 30}).humanize(), "a month", "30 days = a month"); - test.equal(moment.duration({days: 45}).humanize(), "a month", "45 days = a month"); + test.equal(moment.duration({days: 45}).humanize(), "2 months", "45 days = 2 months"); test.equal(moment.duration({days: 46}).humanize(), "2 months", "46 days = 2 months"); test.equal(moment.duration({days: 74}).humanize(), "2 months", "75 days = 2 months"); test.equal(moment.duration({days: 76}).humanize(), "3 months", "76 days = 3 months"); test.equal(moment.duration({months: 1}).humanize(), "a month", "1 month = a month"); test.equal(moment.duration({months: 5}).humanize(), "5 months", "5 months = 5 months"); - test.equal(moment.duration({days: 344}).humanize(), "11 months", "344 days = 11 months"); + test.equal(moment.duration({days: 344}).humanize(), "a year", "344 days = a year"); test.equal(moment.duration({days: 345}).humanize(), "a year", "345 days = a year"); test.equal(moment.duration({days: 547}).humanize(), "a year", "547 days = a year"); test.equal(moment.duration({days: 548}).humanize(), "2 years", "548 days = 2 years"); diff --git a/test/moment/lang.js b/test/moment/lang.js index 405b1a2aa..957b217c7 100644 --- a/test/moment/lang.js +++ b/test/moment/lang.js @@ -202,6 +202,80 @@ exports.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');