From: Rocky Meza Date: Sun, 15 Apr 2012 08:41:21 +0000 (-0600) Subject: Instituted bubbling for Durations X-Git-Tag: 1.6.0~1^2~6^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=407c9484bfd06a5f807668fc76035d29c6265c3e;p=thirdparty%2Fmoment.git Instituted bubbling for Durations This is according to the discussion in #265. --- diff --git a/moment.js b/moment.js index ea468625f..1be02ecbe 100644 --- a/moment.js +++ b/moment.js @@ -28,7 +28,7 @@ timezoneParseRegex = /([\+\-]|\d\d)/gi, VERSION = "1.5.0", shortcuts = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), - durationGetters = 'years|months|weeks|days|hours|minutes|seconds|milliseconds'.split('|'); + durationGetters = 'years|months|days|hours|minutes|seconds|milliseconds'.split('|'); // Moment prototype object function Moment(date, isUTC) { @@ -36,17 +36,64 @@ this._isUTC = !!isUTC; } + function absRound(number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + // Duration Constructor function Duration(duration) { - var data = this._data = {}; - data.years = duration.years || duration.y || 0; - data.months = duration.months || duration.M || 0; - data.weeks = duration.weeks || duration.w || 0; - data.days = duration.days || duration.d || 0; - data.hours = duration.hours || duration.h || 0; - data.minutes = duration.minutes || duration.m || 0; - data.seconds = duration.seconds || duration.s || 0; - data.milliseconds = duration.milliseconds || duration.ms || 0; + var data = this._data = {}, + years = duration.years || duration.y || 0, + months = duration.months || duration.M || 0, + weeks = duration.weeks || duration.w || 0, + days = duration.days || duration.d || 0, + hours = duration.hours || duration.h || 0, + minutes = duration.minutes || duration.m || 0, + seconds = duration.seconds || duration.s || 0, + milliseconds = duration.milliseconds || duration.ms || 0; + + // representation for dateAddRemove + this._milliseconds = milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = months + + years * 12; + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + seconds += absRound(milliseconds / 1000); + + data.seconds = seconds % 60; + minutes += absRound(seconds / 60); + + data.minutes = minutes % 60; + hours += absRound(minutes / 60); + + data.hours = hours % 24; + days += absRound(hours / 24); + + days += weeks * 7; + data.days = days % 30; + + months += absRound(days / 30); + + data.months = months % 12; + years += absRound(months / 12); + + data.years = years; } // left zero fill a number @@ -70,14 +117,10 @@ input = moment.duration(_input); } - ms = input.milliseconds() + - (input.seconds()) * 1e3 + // 1000 - (input.minutes()) * 6e4 + // 1000 * 60 - (input.hours()) * 36e5; // 1000 * 60 * 60 - d = (input.days()) + - (input.weeks()) * 7; - M = (input.months()) + - (input.years()) * 12; + ms = input._milliseconds; + d = input._days; + M = input._months; + if (ms) { date.setTime(+date + ms * adding); } @@ -743,15 +786,14 @@ makeShortcut('year', 'FullYear'); moment.duration.fn = Duration.prototype = { + weeks : function () { + return absRound(this.days() / 7); + }, + valueOf : function () { - return this._data.milliseconds + - (this._data.seconds * 1000) + // 1000 - (this._data.minutes * 60000) + // 60 * 1000 - (this._data.hours * 3600000) + // 60 * 60 * 1000 - (this._data.days * 86400000) + // 24 * 60 * 60 * 1000 - (this._data.weeks * 604800000) + // 7 * 24 * 60 * 60 * 1000 - (this._data.months * 2592000000) + // 30 * 24 * 60 * 60 * 1000 - (this._data.years * 31536000000); // 365 * 24 * 60 * 60 * 1000 + return this._milliseconds + + this._days * 864e5 + + this._months * 2592e6; }, humanize : function (withSuffix) { diff --git a/test/moment/duration.js b/test/moment/duration.js index cd5aa40e5..46971280b 100644 --- a/test/moment/duration.js +++ b/test/moment/duration.js @@ -5,7 +5,7 @@ exports.duration = { var d = moment.duration({ years: 2, months: 3, - weeks: 4, + weeks: 2, days: 1, hours: 8, minutes: 9, @@ -16,8 +16,8 @@ exports.duration = { test.expect(8); test.equal(d.years(), 2, "years"); test.equal(d.months(), 3, "months"); - test.equal(d.weeks(), 4, "weeks"); - test.equal(d.days(), 1, "days"); + test.equal(d.weeks(), 2, "weeks"); + test.equal(d.days(), 15, "days"); // two weeks + 1 day test.equal(d.hours(), 8, "hours"); test.equal(d.minutes(), 9, "minutes"); test.equal(d.seconds(), 20, "seconds"); @@ -130,6 +130,54 @@ exports.duration = { test.done(); }, + "bubble value up" : function(test) { + test.expect(5); + test.equal(moment.duration({milliseconds: 61001}).milliseconds(), 1, "61001 milliseconds has 1 millisecond left over"); + test.equal(moment.duration({milliseconds: 61001}).seconds(), 1, "61001 milliseconds has 1 second left over"); + test.equal(moment.duration({milliseconds: 61001}).minutes(), 1, "61001 milliseconds has 1 minute left over"); + + test.equal(moment.duration({minutes: 350}).minutes(), 50, "350 minutes has 50 minutes left over"); + test.equal(moment.duration({minutes: 350}).hours(), 5, "350 minutes has 5 hours left over"); + test.done(); + }, + + "clipping" : function(test) { + test.expect(18); + test.equal(moment.duration({months: 11}).months(), 11, "11 months is 11 months"); + test.equal(moment.duration({months: 11}).years(), 0, "11 months makes no year"); + test.equal(moment.duration({months: 12}).months(), 0, "12 months is 0 months left over"); + test.equal(moment.duration({months: 12}).years(), 1, "12 months makes 1 year"); + test.equal(moment.duration({months: 13}).months(), 1, "13 months is 1 month left over"); + test.equal(moment.duration({months: 13}).years(), 1, "13 months makes 1 year"); + + test.equal(moment.duration({days: 29}).days(), 29, "29 days is 29 days"); + test.equal(moment.duration({days: 29}).months(), 0, "29 days makes no month"); + test.equal(moment.duration({days: 30}).days(), 0, "30 days is 0 days left over"); + test.equal(moment.duration({days: 30}).months(), 1, "30 days is a month"); + test.equal(moment.duration({days: 31}).days(), 1, "31 days is 1 day left over"); + test.equal(moment.duration({days: 31}).months(), 1, "31 days is a month"); + + test.equal(moment.duration({hours: 23}).hours(), 23, "23 hours is 23 hours"); + test.equal(moment.duration({hours: 23}).days(), 0, "23 hours makes no day"); + test.equal(moment.duration({hours: 24}).hours(), 0, "24 hours is 0 hours left over"); + test.equal(moment.duration({hours: 24}).days(), 1, "24 hours makes 1 day"); + test.equal(moment.duration({hours: 25}).hours(), 1, "25 hours is 1 hour left over"); + test.equal(moment.duration({hours: 25}).days(), 1, "25 hours makes 1 day"); + test.done(); + }, + + "effective equivalency" : function(test) { + test.expect(7); + test.deepEqual(moment.duration({seconds: 1})._data, moment.duration({milliseconds: 1000})._data, "1 second is the same as 1000 milliseconds"); + test.deepEqual(moment.duration({seconds: 60})._data, moment.duration({minutes: 1})._data, "1 minute is the same as 60 seconds"); + test.deepEqual(moment.duration({minutes: 60})._data, moment.duration({hours: 1})._data, "1 hour is the same as 60 minutes"); + test.deepEqual(moment.duration({hours: 24})._data, moment.duration({days: 1})._data, "1 day is the same as 24 hours"); + test.deepEqual(moment.duration({days: 7})._data, moment.duration({weeks: 1})._data, "1 week is the same as 7 days"); + test.deepEqual(moment.duration({days: 30})._data, moment.duration({months: 1})._data, "1 month is the same as 30 days"); + test.deepEqual(moment.duration({months: 12})._data, moment.duration({years: 1})._data, "1 years is the same as 12 months"); + test.done(); + }, + "isDuration" : function(test) { test.expect(3); test.ok(moment.isDuration(moment.duration(12345678)), "correctly says true");