diff --git a/lib/moment-range.js b/lib/moment-range.js index 77d1db8..cfcfe07 100644 --- a/lib/moment-range.js +++ b/lib/moment-range.js @@ -62,18 +62,20 @@ export class DateRange { // reverseBy(interval: Shorthand, options?: { exclusive: bool; }): Iterator; // reverseByRange(range: DateRange, options?: { exclusive: bool; }): Iterator; - by(interval: Shorthand, options?: { exclusive: bool; } = { exclusive: false }): Iterator { + by(interval: Shorthand, options?: { exclusive: bool; step: number; } = { exclusive: false, step: 1 }): Iterator { const range = this; return { [Symbol.iterator]() { - const diff = Math.abs(range.start.diff(range.end, interval)); + const exclusive = options.exclusive || false; + const step = options.step || 1; + const diff = Math.abs(range.start.diff(range.end, interval)) / step; let iteration = 0; return { next() { - const current = range.start.clone().add(iteration, interval); - const done = options.exclusive + const current = range.start.clone().add((iteration * step), interval); + const done = exclusive ? !(iteration < diff) : !(iteration <= diff); @@ -89,9 +91,11 @@ export class DateRange { }; } - byRange(interval: DateRange, options?: { exclusive: bool; } = { exclusive: false }): Iterator { + byRange(interval: DateRange, options?: { exclusive: bool; step: number; } = { exclusive: false, step: 1 }): Iterator { const range = this; - const diff = this.valueOf() / interval.valueOf(); + const step = options.step || 1; + const diff = this.valueOf() / interval.valueOf() / step; + const exclusive = options.exclusive || false; const unit = Math.floor(diff); let iteration = 0; @@ -103,8 +107,8 @@ export class DateRange { return { next() { - const current = moment(range.start.valueOf() + (interval.valueOf() * iteration)); - const done = ((unit === diff) && options.exclusive) + const current = moment(range.start.valueOf() + (interval.valueOf() * iteration * step)); + const done = ((unit === diff) && exclusive) ? !(iteration < unit) : !(iteration <= unit); @@ -183,18 +187,20 @@ export class DateRange { return this.intersect(other) !== null; } - reverseBy(interval: Shorthand, options?: { exclusive: bool; } = { exclusive: false }): Iterator { + reverseBy(interval: Shorthand, options?: { exclusive: bool; step: number; } = { exclusive: false, step: 1 }): Iterator { const range = this; - const diff = Math.abs(range.start.diff(range.end, interval)); return { [Symbol.iterator]() { + const exclusive = options.exclusive || false; + const step = options.step || 1; + const diff = Math.abs(range.start.diff(range.end, interval)) / step; let iteration = 0; return { next() { - const current = range.end.clone().subtract(iteration, interval); - const done = options.exclusive + const current = range.end.clone().subtract((iteration * step), interval); + const done = exclusive ? !(iteration < diff) : !(iteration <= diff); @@ -210,9 +216,11 @@ export class DateRange { }; } - reverseByRange(interval: DateRange, options?: { exclusive: bool; } = { exclusive: false }): Iterator { + reverseByRange(interval: DateRange, options?: { exclusive: bool; step: number; } = { exclusive: false, step: 1 }): Iterator { const range = this; - const diff = this.valueOf() / interval.valueOf(); + const step = options.step || 1; + const diff = this.valueOf() / interval.valueOf() / step; + const exclusive = options.exclusive || false; const unit = Math.floor(diff); let iteration = 0; @@ -224,8 +232,8 @@ export class DateRange { return { next() { - const current = moment(range.end.valueOf() - (interval.valueOf() * iteration)); - const done = ((unit === diff) && options.exclusive) + const current = moment(range.end.valueOf() - (interval.valueOf() * iteration * step)); + const done = ((unit === diff) && exclusive) ? !(iteration < unit) : !(iteration <= unit); diff --git a/lib/moment-range_test.js b/lib/moment-range_test.js index 3e60733..83ab0d2 100644 --- a/lib/moment-range_test.js +++ b/lib/moment-range_test.js @@ -240,6 +240,24 @@ describe('DateRange', function() { acc = Array.from(dr.by('m', options)).map(m => m.utc().format('mm')); expect(acc).to.eql(['00', '01', '02', '03', '04', '05']); }); + + it('should correctly iterate by a given step', function() { + const my1 = moment('2014-04-02T00:00:00.000Z'); + const my2 = moment('2014-04-08T00:00:00.000Z'); + const dr1 = moment.range(my1, my2); + + const acc = Array.from(dr1.by('days', { step: 2 })).map(m => m.utc().format('DD')); + expect(acc).to.eql(['02', '04', '06', '08']); + }); + + it('should correctly iterate by a given step when exclusive', function() { + const my1 = moment('2014-04-02T00:00:00.000Z'); + const my2 = moment('2014-04-08T00:00:00.000Z'); + const dr1 = moment.range(my1, my2); + + const acc = Array.from(dr1.by('days', { exclusive: true, step: 2 })).map(m => m.utc().format('DD')); + expect(acc).to.eql(['02', '04', '06']); + }); }); describe('#reverseBy', function() { @@ -349,6 +367,24 @@ describe('DateRange', function() { acc = Array.from(dr.reverseBy('m', options)).map(m => m.utc().format('mm')); expect(acc).to.eql(['06', '05', '04', '03', '02', '01']); }); + + it('should correctly iterate by a given step', function() { + const my1 = moment('2014-04-02T00:00:00.000Z'); + const my2 = moment('2014-04-08T00:00:00.000Z'); + const dr1 = moment.range(my1, my2); + + const acc = Array.from(dr1.reverseBy('days', { step: 2 })).map(m => m.utc().format('DD')); + expect(acc).to.eql(['08', '06', '04', '02']); + }); + + it('should correctly iterate by a given step when exclusive', function() { + const my1 = moment('2014-04-02T00:00:00.000Z'); + const my2 = moment('2014-04-08T00:00:00.000Z'); + const dr1 = moment.range(my1, my2); + + const acc = Array.from(dr1.reverseBy('days', { exclusive: true, step: 2 })).map(m => m.utc().format('DD')); + expect(acc).to.eql(['08', '06', '04']); + }); }); describe('#byRange', function() { @@ -423,6 +459,28 @@ describe('DateRange', function() { acc = Array.from(dr1.byRange(dr2, { exclusive: true })).map(m => m.utc().format('YYYY-MM-DD')); expect(acc).to.eql(['2014-04-02', '2014-04-03']); }); + + it('should iterate correctly by a given step', function() { + const d1 = new Date(Date.UTC(2012, 2, 2)); + const d2 = new Date(Date.UTC(2012, 2, 6)); + const dr1 = moment.range(d1, d2); + const dr2 = 1000 * 60 * 60 * 24; + + const acc = Array.from(dr1.byRange(dr2, { step: 2 })).map(m => m.utc().format('DD')); + + expect(acc).to.eql(['02', '04', '06']); + }); + + it('should iterate correctly by a given step when exclusive', function() { + const d1 = new Date(Date.UTC(2012, 2, 2)); + const d2 = new Date(Date.UTC(2012, 2, 6)); + const dr1 = moment.range(d1, d2); + const dr2 = 1000 * 60 * 60 * 24; + + const acc = Array.from(dr1.byRange(dr2, { exclusive: true, step: 2 })).map(m => m.utc().format('DD')); + + expect(acc).to.eql(['02', '04']); + }); }); describe('#reverseByRange', function() { @@ -497,6 +555,28 @@ describe('DateRange', function() { acc = Array.from(dr1.reverseByRange(dr2, { exclusive: true })).map(m => m.utc().format('YYYY-MM-DD')); expect(acc).to.eql(['2014-04-04', '2014-04-03']); }); + + it('should iterate correctly by a given step', function() { + const d1 = new Date(Date.UTC(2012, 2, 2)); + const d2 = new Date(Date.UTC(2012, 2, 6)); + const dr1 = moment.range(d1, d2); + const dr2 = 1000 * 60 * 60 * 24; + + const acc = Array.from(dr1.reverseByRange(dr2, { step: 2 })).map(m => m.utc().format('DD')); + + expect(acc).to.eql(['06', '04', '02']); + }); + + it('should iterate correctly by a given step when exclusive', function() { + const d1 = new Date(Date.UTC(2012, 2, 2)); + const d2 = new Date(Date.UTC(2012, 2, 6)); + const dr1 = moment.range(d1, d2); + const dr2 = 1000 * 60 * 60 * 24; + + const acc = Array.from(dr1.reverseByRange(dr2, { exclusive: true, step: 2 })).map(m => m.utc().format('DD')); + + expect(acc).to.eql(['06', '04']); + }); }); describe('#contains()', function() {