Fancy date ranges for Moment.js.
moment-range works in both the browser and node.js.
Install via npm:
npm install --save moment-rangeES6:
import Moment from 'moment';
import { extendMoment } from 'moment-range';
const moment = extendMoment(Moment);CommonJS:
const Moment = require('moment');
const MomentRange = require('moment-range');
const moment = MomentRange.extendMoment(Moment);<script src="moment.js"></script>
<script src="moment-range.js"></script>window['moment-range'].extendMoment(moment);Thanks to the fine people at cdnjs, you can link to moment-range from the cdnjs servers.
Create a date range:
const start = new Date(2012, 0, 15);
const end = new Date(2012, 4, 23);
const range = moment.range(start, end);You can also create a date range with moment objects:
const start = moment('2011-04-15', 'YYYY-MM-DD');
const end = moment('2011-11-27', 'YYYY-MM-DD');
const range = moment.range(start, end);Arrays work too:
const dates = [moment('2011-04-15', 'YYYY-MM-DD'), moment('2011-11-27', 'YYYY-MM-DD')];
const range = moment.range(dates);You can also create a range from an ISO 8601 time interval string:
const timeInterval = '2015-01-17T09:50:04+00:00/2015-04-17T08:29:55+00:00';
const range = moment.range(timeInterval);You can also create a range from the start until the end of a named interval:
const date = moment('2011-04-15', 'YYYY-MM-DD');
const range = date.range('month');You can also create open-ended ranges which go to the earliest or latest possible date:
const rangeUntil = moment.range(null, '2011-05-05');
const rangeFrom = moment.range('2011-03-05', null);
const rangeAllTime = moment.range(null, null);Note: Dates and moment objects both use a timestamp of 00:00:000 if none is
provided. To ensure your range includes any timestamp for the given end date,
use .setHours(23,59,59,999) when constructing a Date object, or
.endOf('day') when constructing a moment object.
You can access the start and end moments of the range easily enough:
const start = new Date(2012, 0, 15);
const end = new Date(2012, 4, 23);
const range = moment.range(start, end);
range.start // moment
range.end // momentCheck if two ranges are touching but not overlapping:
const a = moment('2016-03-15');
const b = moment('2016-03-29');
const c = moment('2016-03-10');
const d = moment('2016-03-15');
const range1 = moment.range(a, b);
const range2 = moment.range(c, d);
range1.adjacent(range2) // trueCalculate the center of a range:
const start = new Date(2011, 2, 5);
const end = new Date(2011, 3, 5);
const dr = moment.range(start, end);
dr.center(); // 1300622400000Check to see if your range contains a date/moment:
const start = new Date(2012, 4, 1);
const end = new Date(2012, 4, 23);
const lol = new Date(2012, 4, 15);
const wat = new Date(2012, 4, 27);
const range = moment.range(start, end);
const range2 = moment.range(lol, wat);
range.contains(lol); // true
range.contains(wat); // falseThe exclusive options is used to indicate if the end of the range should be
excluded when testing for inclusion:
range.contains(end) // true
range.contains(end, { exclusive: false }) // true
range.contains(end, { exclusive: true }) // falseFind out if your moment falls within a date range:
const start = new Date(2012, 4, 1);
const end = new Date(2012, 4, 23);
const when = moment('2012-05-10', 'YYYY-MM-DD');
const range = moment.range(start, end);
when.within(range); // trueDoes it overlap another range?
range.overlaps(range2); // trueInclude adjacent ranges:
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.overlaps(range2) // false
range1.overlaps(range2, { adjacent: false }) // false
range1.overlaps(range2, { adjacent: true }) // trueWhat are the intersecting ranges?
range.intersect(range2); // [moment.range(lol, end)]Include adjacent ranges:
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')]Add/combine/merge overlapping ranges.
range.add(range2); // [moment.range(start, wat)]
const range3 = moment.range(new Date(2012, 3, 1), new Date(2012, 3, 15);
range.add(range3); // [null]Deep clone a range
const start = new Date(2011, 2, 5);
const end = new Date(2011, 3, 5);
const dr = moment.range(start, end);
const dr2 = dr.clone();
dr2.start.add(2, 'days');
dr2.start.toDate() === dr.start.toDate() // falseSubtracting one range from another.
range.subtract(range2); // [moment.range(start, lol)]Each of the iteration methods return an Iterable, providing a convenient and performant interface to iterating over your ranges by a given period.
Iterate over your range by a given period. Any of the units accepted by
moment.js' add method may be used. E.g.: 'years' | 'quarters' | 'months' | 'weeks' | 'days' | 'hours' | 'minutes' | 'seconds' | 'milliseconds'
const range = moment.range('2010-01-01', '2015-01-01');
for (let month of range.by('month')) {
month.format('YYYY-MM-DD');
}
const years = Array.from(range.by('year'));
years.length == 5 // true
years.map(m => m.format('YYYY')) // ['2010', '2011', '2012', '2013', '2014', '2015']Iteration also supports excluding the end value of the range by setting the
exclusive option to true.
const start = new Date(2012, 2, 1);
const end = new Date(2012, 2, 5);
const range1 = moment.range(start, end);
const acc = Array.from(range1.by('day', { exclusive: true }));
acc.length == 4 // trueAdditionally it's possible to iterate by a given step that defaults to 1:
const start = new Date(2012, 2, 2);
const end = new Date(2012, 2, 6);
const range1 = moment.range(start, end);
let acc = Array.from(range1.by('day', { step: 2 }));
acc.map(m => m.format('DD')) // ['02', '04', '06']
acc = Array.from(range1.by('day', { exclusive: true, step: 2 }));
acc.map(m => m.format('DD')) // ['02', '04']const start = new Date(2012, 2, 1);
const two = new Date(2012, 2, 2);
const end = new Date(2012, 2, 5);
const range1 = moment.range(start, end);
const range2 = moment.range(start, two); // One dayIterate by another range:
const acc = Array.from(range1.by(range2));
acc.length == 5 // trueExclude the end value:
const acc = Array.from(range1.by(range2, { exclusive: true }));
acc.length == 4 // trueBy step:
let acc = Array.from(range1.by(range2, { step: 2 }));
acc.map(m => m.format('DD')) // ['01', '03', '05']
acc = Array.from(range1.by(range2, { exlusive, true, step: 2 }));
acc.map(m => m.format('DD')) // ['01', '03']Iterate over a range in reverse:
const range = moment.range('2012-01-01', '2015-01-01');
const acc = Array.from(range.reverseBy('years'));
acc.map(m => m.format('YYYY')) // ['2015', '2014', '2013', '2012']Exclude the end value:
const range = moment.range('2012-01-01', '2015-01-01');
const acc = Array.from(range.reverseBy('years', { exclusive: true }));
acc.map(m => m.format('YYYY')) // ['2015', '2014', '2013']By step:
const start = new Date(2012, 2, 2);
const end = new Date(2012, 2, 6);
const range1 = moment.range(start, end);
let acc = Array.from(range1.reverseBy('day', { step: 2 }));
acc.map(m => m.format('DD')) // ['06', '04', '02']
acc = Array.from(range1.reverseBy('day', { exclusive: true, step: 2 }));
acc.map(m => m.format('DD')) // ['06', '04']const start = new Date(2012, 2, 1);
const two = new Date(2012, 2, 2);
const end = new Date(2012, 2, 5);
const range1 = moment.range(start, end);
const range2 = moment.range(start, two); // One dayIterate by another range in reverse:
const acc = Array.from(range1.by(range2));
acc.length == 5 // true
acc.map(m => m.format('DD')) // ['05', '04', '03', '02', '01']Exclude the end value:
const acc = Array.from(range1.by(range2, { exclusive: true }));
acc.length == 4 // true
acc.map(m => m.format('DD')) // ['05', '04', '03', '02']By step:
let acc = Array.from(range1.reverseByRange(range2, { step: 2 }));
acc.map(m => m.format('DD')) // ['05', '03', '01']
acc = Array.from(range1.reverseByRange(range2, { exlusive, true, step: 2 }));
acc.map(m => m.format('DD')) // ['05', '03']Compare range lengths or add them together with simple math:
const range1 = moment.range(new Date(2011, 2, 5), new Date(2011, 3, 15));
const range2 = moment.range(new Date(1995, 0, 1), new Date(1995, 12, 25));
range2 > range1 // true
range1 + range2 // duration of both ranges in milliseconds
Math.abs(range1 - range2); // difference of ranges in millisecondsCheck if two ranges are the same, i.e. their starts and ends are the same:
const range1 = moment.range(new Date(2011, 2, 5), new Date(2011, 3, 15));
const range2 = moment.range(new Date(2011, 2, 5), new Date(2011, 3, 15));
const range3 = moment.range(new Date(2011, 3, 5), new Date(2011, 6, 15));
range1.isSame(range2); // true
range2.isSame(range3); // false
range1.isEqual(range2); // true
range2.isEqual(range3); // falseThe difference of the entire range given various units.
Any of the units accepted by moment.js' add method may be used.
const start = new Date(2011, 2, 5);
const end = new Date(2011, 5, 5);
const dr = moment.range(start, end);
dr.diff('months'); // 3
dr.diff('days'); // 92
dr.diff(); // 7945200000Optionally you may specify if the difference should be rounded, by default it mimics moment-js' behaviour and rounds the values:
const d1 = new Date(Date.UTC(2011, 4, 1));
const d2 = new Date(Date.UTC(2011, 4, 5, 12));
const range = moment.range(d1, d2);
dr.diff('days') // 4
dr.diff('days', false) // 4
dr.diff('days', true) // 4.5#duration is an alias for #diff and they may be used interchangeably.
Converts the DateRange to an Array of the start and end Date objects.
const start = new Date(2011, 2, 5);
const end = new Date(2011, 5, 5);
const dr = moment.range(start, end);
dr.toDate(); // [new Date(2011, 2, 5), new Date(2011, 5, 5)]Converting a DateRange to a String will format it as an ISO 8601 time
interval:
const start = '2015-01-17T09:50:04+00:00';
const end = '2015-04-17T08:29:55+00:00';
const range = moment.range(moment.utc(start), moment.utc(end));
range.toString() // '2015-01-17T09:50:04+00:00/2015-04-17T08:29:55+00:00'The difference between the end date and start date in milliseconds.
const start = new Date(2011, 2, 5);
const end = new Date(2011, 5, 5);
const range = moment.range(start, end);
range.valueOf(); // 7945200000Clone this bad boy:
git clone https://git@github.com/gf3/moment-range.gitInstall the dependencies:
npm installDo all the things!
npm run test
npm run lint- Adam Biggs (http://lightmaker.com)
- Mats Julian Olsen
- Matt Patterson (http://reprocessed.org/)
- Wilgert Velinga (http://neocles.io)
- Tomasz Bak (http://twitter.com/tomaszbak)
- Stuart Kelly
- Jeremy Forsythe
- Александр Гренишин
- @scotthovestadt
- Thomas van Lankveld
- nebel
- Kevin Ross (http://www.alienfast.com)
- Thomas Walpole
- Jonathan Kim (http://jkimbo.co.uk)
- Tymon Tobolski (http://teamon.eu)
- Aristide Niyungeko
- Bradley Ayers
- Ross Hadden (http://rosshadden.github.com/resume)
- Victoria French
- Jochen Diekenbrock
moment-range is UNLICENSED.