Natural Preference for Minification

    moment-range
    TypeScript icon, indicating that this package has built-in type declarations

    4.0.2 • Public • Published

    moment-range CircleCI

    Fancy date ranges for Moment.js.

    Installation

    moment-range works in both the browser and node.js.

    Node / NPM

    Install via npm:

    npm install --save moment-range

    ES6:

    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);

    Browser

    <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.

    Older browsers and IE11

    This library makes use of Symbol.iterator to provide the iteration protocols now that there is broad support for them, if you need to support older browsers (specifically IE11) you will need to include a polyfill. Any of the following should work, depending on your project configuration:

    Examples

    Create

    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');
    const rangeAllTime = moment.range();

    Note that any falsy value except 0 is treated as a missing date, resulting in an open-ended range.

    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.

    rangeFromInterval

    You can also create a range between an interval and a specified date. This accepts positive or negative values for count and the date will default to now if not provided.

    const interval = 'month';
    const count = 4;
    const date = moment('2017-07-20');
     
    const range1 = moment.rangeFromInterval(interval, count, date);  // moment.range('2017-07-20', '2017-11-20')
    const range2 = moment.rangeFromInterval('month', -2, date);      // moment.range('2017-05-20', '2017-07-20')

    Note: The date can be provided as a Date, String, or Moment. When using a negative interval, the date provided will be set as the end of the range.

    parseZoneRange

    DEPRECATED in 4.0.0: Replaced by rangeFromISOString to follow naming conventions.

    rangeFromISOString

    Converts an ISO 8601 time interval string into a date range while preserving the time zones using moment.parseZone.

    const interval = '2015-01-17T09:50:00+03:00/2015-04-17T08:29:55-04:00';
    const range = moment.rangeFromISOString(interval);
     
    range.toString(); // '2015-01-17T09:50:00+03:00/2015-04-17T08:29:55-04:00'

    Attributes

    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  // moment

    Querying

    Many of the following examples make use of these moments:

    const a = moment('2016-03-10');
    const b = moment('2016-03-15');
    const c = moment('2016-03-29');
    const d = moment('2016-04-01');

    Adjacent

    Check if two ranges are touching but not overlapping:

     
    const range1 = moment.range(a, b);
    const range2 = moment.range(b, c);
    const range3 = moment.range(c, d);
     
    range1.adjacent(range2) // true
    range1.adjacent(range3) // false

    Center

    Calculate the center of a range:

    const start = new Date(2011, 2, 5);
    const end   = new Date(2011, 3, 5);
    const range = moment.range(start, end);
     
    range.center(); // 1300622400000

    Contains

    Check to see if your range contains a date/moment. By default the start and end dates are included in the search. E.g.:

    const range = moment.range(a, c);
     
    range.contains(a); // true
    range.contains(b); // true
    range.contains(c); // true
    range.contains(d); // false

    You can also control whether the start or end dates should be excluded from the search with the excludeStart and excludeEnd options:

    const range = moment.range(a, c);
     
    range.contains(a); // true
    range.contains(a, { excludeStart: true }); // false
    range.contains(c); // true
    range.contains(c, { excludeEnd: true; }); // false

    DEPRECATED in 4.0.0: The exclusive options is used to indicate if the start/end of the range should be excluded when testing for inclusion:

    Note: You can obtain the same functionality by setting { excludeStart: true, excludeEnd: true }

    range.contains(c); // true
    range.contains(c, { exclusive: false }); // true
    range.contains(c, { exclusive: true }); // false

    Within

    Find out if your moment falls within a date range:

    const range = moment.range(a, c);
     
    b.within(range); // true

    Overlaps

    Does it overlap another range?

    const range1 = moment.range(a, c);
    const range2 = moment.range(b, d);
    range1.overlaps(range2); // true

    Include adjacent ranges:

    const range1 = moment.range(a, b);
    const range2 = moment.range(b, c);
     
    range1.overlaps(range2)                      // false
    range1.overlaps(range2, { adjacent: false }) // false
    range1.overlaps(range2, { adjacent: true })  // true

    Intersect

    What is the intersecting range?

    const range1 = moment.range(a, c);
    const range2 = moment.range(b, d);
    range1.intersect(range2); // moment.range(b, c)

    IsRange

    Is it a Range?

    moment.isRange(range); // true
    moment.isRange(IamNotRange); // false

    Manipulation

    Add

    Add/combine/merge overlapping or adjacent ranges.

    const range1 = moment.range(a, c);
    const range2 = moment.range(b, d);
    range1.add(range2); // moment.range(a, d)
     
    const range3 = moment.range(a, b);
    const range4 = moment.range(c, d);
    range3.add(range4); // null

    Include adjacent ranges:

    const range1 = moment.range(a, b);
    const range2 = moment.range(b, c);
     
    range1.add(range2); // null
    range1.add(range2, { adjacent: false }); // null
    range1.add(range2, { adjacent: true }); // moment.range(a, c)

    Clone

    Deep clone a range

    const range1 = moment.range(a, d);
     
    const range2 = range1.clone();
    range2.start.add(2, 'days');
     
    range1.start.toDate().getTime() === range2.start.toDate().getTime() // false

    SnapTo

    Snap the start and end of a range to a given interval.

    const start = moment('2018-01-25 17:05:33');
    const end = moment('2018-01-28 06:10:00');
     
    const range1 = moment.range(start, end);
    const range2 = range1.snapTo('day'); // 2018-01-25T00:00:00 -> 2018-01-28T23:59:59
     
    range1.diff('days'); // 2
    range2.diff('days'); // 3

    Subtract

    Subtracting one range from another.

    const range_ab = moment.range(a, b);
    const range_bc = moment.range(b, c);
    const range_cd = moment.range(c, d);
    const range_ad = moment.range(a, d);
    range_ad.subtract(range_bc); // [moment.range(a, b) moment.range(c, d)]
    range_ac.subtract(range_bc); // [moment.range(a, b)]
    range_ab.subtract(range_cd); // [moment.range(a, b)]
    range_bc.subtract(range_bd); // [null]

    Iteration

    Each of the iteration methods returns an Iterable, providing a convenient and performant interface to iterating over your ranges by a given period.

    by

    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 == 6 // true
    years.map(m => m.format('YYYY')) // ['2010', '2011', '2012', '2013', '2014', '2015']

    Iteration also supports excluding the final time slice of the range by setting the excludeEnd option to true. In the example below, the 5:00 -> 6:00 time slice is omitted.

    const range = moment.range('2018-01-01 00:00', '2018-01-01 05:30');
     
    const hours = Array.from(range.by('hour', { excludeEnd: true }));
    hours.length == 5 // true
    hours.map(m => m.format('HH:mm')) // ['00:00', '01:00', '02:00', '03:00', '04:00']

    Additionally 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', { excludeEnd: true, step: 2 }));
     
    acc.map(m => m.format('DD')) // ['02', '04']

    You can iterate over the span of a range for a period that is entered but not complete by using the snapTo() method:

    const start = moment("2017-01-01T13:30:00");
    const end = moment("2017-01-05T01:45:12");
    const r1 = moment.range(start, end);
    const r2 = r1.snapTo('day');
     
    Array.from(r1.by('days')).map(m => m.format('DD')); // ['01', '02', '03', '04']
    Array.from(r2.by('days')).map(m => m.format('DD')); // ['01', '02', '03', '04', '05']

    DEPRECATED in 4.0.0: The exclusive options is used to indicate if the end of the range should be excluded when testing for inclusion:

    Note: You can obtain the same functionality by setting { excludeEnd: true }

    byRange

    const start = new Date(2012, 2, 1); // 1st
    const two   = new Date(2012, 2, 2); // 2nd
    const end   = new Date(2012, 2, 5); // 5th
    const range1 = moment.range(start, end);
    const range2 = moment.range(start, two); // One day

    Iterate by another range:

    const acc = Array.from(range1.byRange(range2));
     
    acc.length == 5 // true
    acc.map(m => m.format('DD')) // ['01','02','03','04','05']

    Exclude the end time slice:

    const acc = Array.from(range1.byRange(range2, { excludeEnd: true }));
     
    acc.length == 4 // true
    acc.map(m => m.format('DD')) // ['01','02','03','04']

    By step:

    let acc = Array.from(range1.byRange(range2, { step: 2 }));
     
    acc.map(m => m.format('DD')) // ['01', '03', '05']
     
    acc = Array.from(range1.byRange(range2, { excludeEnd, true, step: 2 }));
     
    acc.map(m => m.format('DD')) // ['01', '03']

    DEPRECATED in 4.0.0: The exclusive options is used to indicate if the end of the range should be excluded when testing for inclusion:

    Note: You can obtain the same functionality by setting { excludeEnd: true }

    reverseBy

    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 start time slice:

    const range = moment.range('2012-01-01', '2015-01-01');
    const acc = Array.from(range.reverseBy('years', { excludeStart: 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', { excludeStart: true, step: 2 }));
     
    acc.map(m => m.format('DD')) // ['06', '04']

    DEPRECATED in 4.0.0: The exclusive options is used to indicate if the start of the range should be excluded when testing for inclusion:

    Note: You can obtain the same functionality by setting { excludeStart: true }

    reverseByRange

    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 day

    Iterate by another range in reverse:

    const acc = Array.from(range1.reverseByRange(range2));
     
    acc.length == 5 // true
    acc.map(m => m.format('DD')) // ['05', '04', '03', '02', '01']

    Exclude the start value:

    const acc = Array.from(range1.reverseByRange(range2, { excludeStart: 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, { excludeStart: true, step: 2 }));
     
    acc.map(m => m.format('DD')) // ['05', '03']

    DEPRECATED in 4.0.0: The exclusive options is used to indicate if the start of the range should be excluded when testing for inclusion:

    Note: You can obtain the same functionality by setting { excludeStart: true }

    Compare

    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 milliseconds

    Equality

    Check 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); // false

    Difference

    The 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 range = moment.range(start, end);
     
    range.diff('months'); // 3
    range.diff('days');   // 92
    range.diff();         // 7945200000

    Optionally you may specify if the difference should not be truncated. By default it mimics moment-js' behaviour and truncates 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);
     
    range.diff('days')        // 4
    range.diff('days', false) // 4
    range.diff('days', true)  // 4.75

    #duration is an alias for #diff and they may be used interchangeably.

    Conversion

    toDate

    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 range = moment.range(start, end);
     
    range.toDate(); // [new Date(2011, 2, 5), new Date(2011, 5, 5)]

    toString

    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'

    valueOf

    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(); // 7945200000

    Running Tests

    Clone this bad boy:

    git clone https://git@github.com/rotaready/moment-range.git

    Install the dependencies:

    yarn install

    Do all the things!

    yarn run check
    yarn run test
    yarn run lint

    Contributors

    License

    moment-range is UNLICENSED.

    Keywords

    none

    Install

    npm i moment-range

    DownloadsWeekly Downloads

    256,801

    Version

    4.0.2

    License

    Unlicense

    Unpacked Size

    131 kB

    Total Files

    9

    Last publish

    Collaborators

    • avatar
    • avatar
    • avatar
    • avatar
    • avatar