diff --git a/README.md b/README.md index c23afab..476381d 100644 --- a/README.md +++ b/README.md @@ -256,6 +256,22 @@ What are the intersecting ranges? range.intersect(range2); // [moment.range(lol, end)] ``` +Include adjacent ranges: + +``` js +const a = moment('2016-03-15'); +const b = moment('2016-03-20'); +const c = moment('2016-03-20'); +const d = moment('2016-03-25'); + +const range1 = moment.range(a, b); +const range2 = moment.range(c, d); + +range1.intersect(range2) // null +range1.intersect(range2, { adjacent: false }) // null +range1.intersect(range2, { adjacent: true }) // [moment.range('2016-03,20', '2016-03,20')] +``` + ### Manipulation #### Add diff --git a/lib/moment-range.js b/lib/moment-range.js index 15209e2..fa61ceb 100644 --- a/lib/moment-range.js +++ b/lib/moment-range.js @@ -151,7 +151,7 @@ export class DateRange { return this.diff(unit, rounded); } - intersect(other) { + intersect(other, options = { adjacent: false }) { const start = this.start.valueOf(); const end = this.end.valueOf(); const oStart = other.start.valueOf(); @@ -169,6 +169,14 @@ export class DateRange { else if ((start <= oStart) && (oStart <= oEnd) && (oEnd <= end)) { return other; } + else if (options.adjacent) { + if ((start <= end) && (end == oStart) && (oStart <= oEnd)) { + return new this.constructor(end, end); + } + else if ((oStart <= oEnd) && (oEnd == start) && (start <= end)) { + return new this.constructor(oEnd, oEnd); + } + } return null; } diff --git a/lib/moment-range_test.js b/lib/moment-range_test.js index 6f038c8..11b8590 100644 --- a/lib/moment-range_test.js +++ b/lib/moment-range_test.js @@ -12,6 +12,7 @@ describe('Moment', function() { let dr = moment.range(new Date(Date.UTC(2011, 2, 5)), new Date(Date.UTC(2011, 5, 5))); const m1 = moment('2011-04-15', 'YYYY-MM-DD'); const m2 = moment('2012-12-25', 'YYYY-MM-DD'); + const smr = moment.range(m2, m2); const mStart = moment('2011-03-05', 'YYYY-MM-DD'); const mEnd = moment('2011-06-05', 'YYYY-MM-DD'); const or = moment.range(null, '2011-05-05'); @@ -29,6 +30,11 @@ describe('Moment', function() { expect(dr.start.valueOf()).to.equal(moment(m1).startOf('year').valueOf()); expect(dr.end.valueOf()).to.equal(moment(m1).endOf('year').valueOf()); }); + + it('should support single moment ranges', function() { + expect(smr.start.valueOf()).to.equal(moment(m2).valueOf()); + expect(smr.end.valueOf()).to.equal(moment(m2).valueOf()); + }); }); describe('#within()', function() { @@ -45,6 +51,10 @@ describe('Moment', function() { expect(mStart.within(dr)).to.be(true); expect(mEnd.within(dr)).to.be(true); }); + + it('should consider single moment to be within single moment range', function() { + expect(m2.within(smr)).to.be(true); + }); }); }); @@ -188,6 +198,28 @@ describe('DateRange', function() { expect(range1.adjacent(range2)).to.be(false); }); + + it('should correctly indicate when a.end == single moment range', function() { + const a = moment('15-Mar-2016'); + const b = moment('20-Mar-2016'); + const d = moment('20-Mar-2016'); + + const range1 = moment.range(a, b); + const range2 = moment.range(d, d); + + expect(range1.adjacent(range2)).to.be(true); + }); + + it('should correctly indicate when a.start == single moment range', function() { + const a = moment('15-Mar-2016'); + const c = moment('15-Mar-2016'); + const d = moment('30-Mar-2016'); + + const range1 = moment.range(a, a); + const range2 = moment.range(c, d); + + expect(range1.adjacent(range2)).to.be(true); + }); }); describe('#clone()', function() { @@ -224,6 +256,28 @@ describe('DateRange', function() { expect(acc.length).to.be(5); }); + it('should return a valid iterator for single moment range', function() { + const d1 = new Date(Date.UTC(2012, 2, 1)); + const dr1 = moment.range(d1, d1); + + // Splat + const i1 = dr1.by('day'); + expect([...i1].length).to.be(1); + + // For/of + const i2 = dr1.by('day'); + let i = 0; + for (let n of i2) { + i++; + } + expect(i).to.be(1); + + // Array.from + const i3 = dr1.by('day'); + const acc = Array.from(i3).map(m => m.utc().format('YYYY-MM-DD')); + expect(acc).to.eql([moment(d1).utc().format('YYYY-MM-DD')]); + }); + it('should iterate correctly by shorthand string', function() { const d1 = new Date(Date.UTC(2012, 2, 1)); const d2 = new Date(Date.UTC(2012, 2, 5)); @@ -351,6 +405,28 @@ describe('DateRange', function() { expect(acc.length).to.be(5); }); + it('should return a valid iterator for single moment range', function() { + const d1 = new Date(Date.UTC(2012, 2, 1)); + const dr1 = moment.range(d1, d1); + + // Splat + const i1 = dr1.reverseBy('day'); + expect([...i1].length).to.be(1); + + // For/of + const i2 = dr1.reverseBy('day'); + let i = 0; + for (let n of i2) { + i++; + } + expect(i).to.be(1); + + // Array.from + const i3 = dr1.reverseBy('day'); + const acc = Array.from(i3).map(m => m.utc().format('YYYY-MM-DD')); + expect(acc).to.eql([moment(d1).utc().format('YYYY-MM-DD')]); + }); + it('should iterate correctly by shorthand string', function() { const d1 = new Date(Date.UTC(2012, 2, 1)); const d2 = new Date(Date.UTC(2012, 2, 5)); @@ -481,6 +557,31 @@ describe('DateRange', function() { expect(acc.length).to.be(5); }); + it('should return a valid iterator for single moment range', function() { + const d1 = new Date(Date.UTC(2012, 2, 1)); + const d3 = new Date(Date.UTC(2012, 2, 15)); + const d4 = new Date(Date.UTC(2012, 2, 16)); + const dr1 = moment.range(d1, d1); + const dr2 = moment.range(d3, d4); + + // Splat + const i1 = dr1.byRange(dr2); + expect([...i1].length).to.be(1); + + // For/of + const i2 = dr1.byRange(dr2); + let i = 0; + for (let n of i2) { + i++; + } + expect(i).to.be(1); + + // Array.from + const i3 = dr1.byRange(dr2); + const acc = Array.from(i3).map(m => m.utc().format('YYYY-MM-DD')); + expect(acc).to.eql([moment(d1).utc().format('YYYY-MM-DD')]); + }); + it('should iterate correctly by range', function() { const d1 = new Date(Date.UTC(2012, 2, 1)); const d2 = new Date(Date.UTC(2012, 2, 5)); @@ -577,6 +678,31 @@ describe('DateRange', function() { expect(acc.length).to.be(5); }); + it('should return a valid iterator for single moment range', function() { + const d1 = new Date(Date.UTC(2012, 2, 1)); + const d3 = new Date(Date.UTC(2012, 2, 15)); + const d4 = new Date(Date.UTC(2012, 2, 16)); + const dr1 = moment.range(d1, d1); + const dr2 = moment.range(d3, d4); + + // Splat + const i1 = dr1.reverseByRange(dr2); + expect([...i1].length).to.be(1); + + // For/of + const i2 = dr1.reverseByRange(dr2); + let i = 0; + for (let n of i2) { + i++; + } + expect(i).to.be(1); + + // Array.from + const i3 = dr1.reverseByRange(dr2); + const acc = Array.from(i3).map(m => m.utc().format('YYYY-MM-DD')); + expect(acc).to.eql([moment(d1).utc().format('YYYY-MM-DD')]); + }); + it('should iterate correctly by range', function() { const d1 = new Date(Date.UTC(2012, 2, 1)); const d2 = new Date(Date.UTC(2012, 2, 5)); @@ -669,6 +795,13 @@ describe('DateRange', function() { expect(dr2.contains(dr1)).to.be(false); }); + it('should work with single moment range', function() { + const dr = moment.range(m1, m1); + + expect(dr.contains(m1)).to.be(true); + expect(dr.contains(m4)).to.be(false); + }); + it('should be an inclusive comparison', function() { const dr1 = moment.range(m1, m4); @@ -687,6 +820,13 @@ describe('DateRange', function() { expect(dr1.contains(m2, { exclusive: false })).to.be(true); expect(dr1.contains(m2)).to.be(true); }); + + it('should work with single moment range when the exclusive param is set', function() { + const dr = moment.range(m1, m1); + + expect(dr.contains(m1, { exclusive: false })).to.be(true); + expect(dr.contains(m1, { exclusive: true })).to.be(false); + }); }); describe('#overlaps()', function() { @@ -714,6 +854,22 @@ describe('DateRange', function() { expect(range1.overlaps(range2, { adjacent: false })).to.be(false); expect(range1.overlaps(range2, { adjacent: true })).to.be(true); }); + + it('should work with single moment range', function() { + const a = moment('15-Mar-2016'); + const b = moment('25-Mar-2016'); + const c = moment('20-Mar-2016'); + const d = moment('25-Mar-2016'); + + const range1 = moment.range(a, b); + const range2 = moment.range(c, c); + const range3 = moment.range(d, d); + + expect(range1.overlaps(range2)).to.be(true); + expect(range3.overlaps(range1)).to.be(false); + expect(range3.overlaps(range1, { adjacent: false })).to.be(false); + expect(range1.overlaps(range3, { adjacent: true })).to.be(true); + }); }); describe('#intersect()', function() { @@ -727,6 +883,53 @@ describe('DateRange', function() { const dr2 = moment.range(d6, d8); expect(dr1.intersect(dr2).isSame(moment.range(d6, d7))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(moment.range(d6, d7))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(moment.range(d6, d7))).to.be(true); + }); + + it('should work with [---{}] overlaps where (a=[], b={} is smr)', function() { + const dr1 = moment.range(d5, d7); + const dr2 = moment.range(d7, d7); + + expect(dr1.intersect(dr2).isSame(moment.range(d7, d7))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(moment.range(d7, d7))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(moment.range(d7, d7))).to.be(true); // AQUI + }); + + it('should work with [{}---] overlaps where (a=[], b={} is smr)', function() { + const dr1 = moment.range(d5, d7); + const dr2 = moment.range(d5, d5); + + expect(dr1.intersect(dr2).isSame(moment.range(d5, d5))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(moment.range(d5, d5))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(moment.range(d5, d5))).to.be(true); // AQUI + }); + + it('should work with [---{}---] overlaps where (a=[], b={} is smr)', function() { + const dr1 = moment.range(d5, d7); + const dr2 = moment.range(d6, d6); + + expect(dr1.intersect(dr2).isSame(moment.range(d6, d6))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(moment.range(d6, d6))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(moment.range(d6, d6))).to.be(true); + }); + + it('should work with {} [---] overlaps where (a=[], b={} is smr)', function() { + const dr1 = moment.range(d6, d8); + const dr2 = moment.range(d5, d5); + + expect(dr1.intersect(dr2)).to.be(null); + expect(dr1.intersect(dr2, { adjacent: false })).to.be(null); + expect(dr1.intersect(dr2, { adjacent: true })).to.be(null); + }); + + it('should work with [---] {} overlaps where (a=[], b={} is smr)', function() { + const dr1 = moment.range(d5, d7); + const dr2 = moment.range(d8, d8); + + expect(dr1.intersect(dr2)).to.be(null); + expect(dr1.intersect(dr2, { adjacent: false })).to.be(null); + expect(dr1.intersect(dr2, { adjacent: true })).to.be(null); }); it('should work with {---[==}---] overlaps where (a=[], b={})', function() { @@ -734,6 +937,8 @@ describe('DateRange', function() { const dr2 = moment.range(d5, d7); expect(dr1.intersect(dr2).isSame(moment.range(d6, d7))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(moment.range(d6, d7))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(moment.range(d6, d7))).to.be(true); }); it('should work with [{===]---} overlaps where (a=[], b={})', function() { @@ -741,6 +946,8 @@ describe('DateRange', function() { const dr2 = moment.range(d5, d7); expect(dr1.intersect(dr2).isSame(moment.range(d5, d6))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(moment.range(d5, d6))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(moment.range(d5, d6))).to.be(true); }); it('should work with {[===}---] overlaps where (a=[], b={})', function() { @@ -748,6 +955,8 @@ describe('DateRange', function() { const dr2 = moment.range(d5, d6); expect(dr1.intersect(dr2).isSame(moment.range(d5, d6))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(moment.range(d5, d6))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(moment.range(d5, d6))).to.be(true); }); it('should work with [---{===]} overlaps where (a=[], b={})', function() { @@ -755,6 +964,8 @@ describe('DateRange', function() { const dr2 = moment.range(d6, d7); expect(dr1.intersect(dr2).isSame(moment.range(d6, d7))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(moment.range(d6, d7))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(moment.range(d6, d7))).to.be(true); }); it('should work with {---[===}] overlaps where (a=[], b={})', function() { @@ -762,6 +973,8 @@ describe('DateRange', function() { const dr2 = moment.range(d5, d7); expect(dr1.intersect(dr2).isSame(moment.range(d6, d7))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(moment.range(d6, d7))).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(moment.range(d6, d7))).to.be(true); }); it('should work with [---] {---} overlaps where (a=[], b={})', function() { @@ -769,6 +982,8 @@ describe('DateRange', function() { const dr2 = moment.range(d7, d8); expect(dr1.intersect(dr2)).to.be(null); + expect(dr1.intersect(dr2, { adjacent: false })).to.be(null); + expect(dr1.intersect(dr2, { adjacent: true })).to.be(null); }); it('should work with {---} [---] overlaps where (a=[], b={})', function() { @@ -776,6 +991,8 @@ describe('DateRange', function() { const dr2 = moment.range(d5, d6); expect(dr1.intersect(dr2)).to.be(null); + expect(dr1.intersect(dr2, { adjacent: false })).to.be(null); + expect(dr1.intersect(dr2, { adjacent: true })).to.be(null); }); it('should work with [---]{---} overlaps where (a=[], b={})', function() { @@ -783,12 +1000,17 @@ describe('DateRange', function() { const dr2 = moment.range(d6, d7); expect(dr1.intersect(dr2)).to.be(null); + expect(dr1.intersect(dr2, { adjacent: false })).to.be(null); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(moment.range(d6, d6))).to.be(true); // AQUI }); it('should work with {---}[---] overlaps where (a=[], b={})', function() { const dr1 = moment.range(d6, d7); const dr2 = moment.range(d5, d6); + expect(dr1.intersect(dr2)).to.be(null); + expect(dr1.intersect(dr2, { adjacent: false })).to.be(null); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(moment.range(d6, d6))).to.be(true); // AQUI }); it('should work with {--[===]--} overlaps where (a=[], b={})', function() { @@ -796,6 +1018,8 @@ describe('DateRange', function() { const dr2 = moment.range(d5, d8); expect(dr1.intersect(dr2).isSame(dr1)).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(dr1)).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(dr1)).to.be(true); }); it('should work with [--{===}--] overlaps where (a=[], b={})', function() { @@ -803,6 +1027,8 @@ describe('DateRange', function() { const dr2 = moment.range(d6, d7); expect(dr1.intersect(dr2).isSame(dr2)).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(dr2)).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(dr2)).to.be(true); }); it('should work with [{===}] overlaps where (a=[], b={})', function() { @@ -810,6 +1036,8 @@ describe('DateRange', function() { const dr2 = moment.range(d5, d6); expect(dr1.intersect(dr2).isSame(dr2)).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(dr2)).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(dr2)).to.be(true); }); it('should work with [--{}--] overlaps where (a=[], b={})', function() { @@ -817,6 +1045,8 @@ describe('DateRange', function() { const dr2 = moment.range(d5, d7); expect(dr1.intersect(dr2).isSame(dr1)).to.be(true); + expect(dr1.intersect(dr2, { adjacent: false }).isSame(dr1)).to.be(true); + expect(dr1.intersect(dr2, { adjacent: true }).isSame(dr1)).to.be(true); }); }); @@ -1022,6 +1252,13 @@ describe('DateRange', function() { expect(dr1.isSame(dr2)).to.be(false); }); + + it('should true if both single moment range are the same', function() { + const dr1 = moment.range(d1, d1); + const dr2 = moment.range(d1, d1); + + expect(dr1.isSame(dr2)).to.be(true); + }); }); describe('#toString()', function() { @@ -1047,6 +1284,12 @@ describe('DateRange', function() { expect((dr1 > dr2)).to.be(true); }); + + it('should be zero for single moment range', function() { + const dr = moment.range(d1, d1); + + expect(dr.valueOf()).to.eql(0); + }); }); describe('#toDate()', function() {