Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
moment-range
Advanced tools
The moment-range npm package extends the functionality of the Moment.js library to handle date ranges. It allows you to create, manipulate, and query ranges of dates with ease.
Creating Date Ranges
This feature allows you to create a date range by specifying a start and end date. The code sample demonstrates how to create a date range from January 1, 2023, to December 31, 2023.
const moment = require('moment');
const { extendMoment } = require('moment-range');
const momentRange = extendMoment(moment);
const start = moment('2023-01-01');
const end = moment('2023-12-31');
const range = momentRange.range(start, end);
console.log(range.toString());
Checking if a Date is within a Range
This feature allows you to check if a specific date falls within a given date range. The code sample checks if June 15, 2023, is within the range from January 1, 2023, to December 31, 2023.
const moment = require('moment');
const { extendMoment } = require('moment-range');
const momentRange = extendMoment(moment);
const start = moment('2023-01-01');
const end = moment('2023-12-31');
const range = momentRange.range(start, end);
const date = moment('2023-06-15');
console.log(range.contains(date)); // true
Iterating over Date Ranges
This feature allows you to iterate over each day within a date range. The code sample iterates over each day from January 1, 2023, to January 7, 2023, and prints the date.
const moment = require('moment');
const { extendMoment } = require('moment-range');
const momentRange = extendMoment(moment);
const start = moment('2023-01-01');
const end = moment('2023-01-07');
const range = momentRange.range(start, end);
for (let day of range.by('day')) {
console.log(day.format('YYYY-MM-DD'));
}
Date Range Intersections
This feature allows you to find the intersection of two date ranges. The code sample finds the intersection of two date ranges: January 1, 2023, to June 30, 2023, and April 1, 2023, to December 31, 2023.
const moment = require('moment');
const { extendMoment } = require('moment-range');
const momentRange = extendMoment(moment);
const range1 = momentRange.range('2023-01-01', '2023-06-30');
const range2 = momentRange.range('2023-04-01', '2023-12-31');
const intersection = range1.intersect(range2);
console.log(intersection.toString()); // 2023-04-01 - 2023-06-30
date-fns is a modern JavaScript date utility library that provides a comprehensive set of functions for manipulating dates. Unlike moment-range, date-fns is modular, allowing you to import only the functions you need. It also has a smaller footprint and better performance.
Luxon is a modern JavaScript library for working with dates and times. It is a successor to Moment.js and offers a more powerful and flexible API. Luxon supports date ranges through its Interval class, which provides similar functionality to moment-range.
Day.js is a minimalist JavaScript library that parses, validates, manipulates, and displays dates and times. It is a lightweight alternative to Moment.js with a similar API. Day.js can be extended with plugins to support date range functionality, making it a versatile option.
Fancy date ranges for Moment.js.
moment-range works in both the browser and node.js.
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);
<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.
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:
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.
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.
DEPRECATED in 4.0.0
: Replaced by rangeFromISOString
to follow naming conventions.
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'
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
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');
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
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
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
Find out if your moment falls within a date range:
const range = moment.range(a, c);
b.within(range); // true
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
What is the intersecting range?
const range1 = moment.range(a, c);
const range2 = moment.range(b, d);
range1.intersect(range2); // moment.range(b, c)
Is it a Range?
moment.isRange(range); // true
moment.isRange(IamNotRange); // false
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)
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
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
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]
Each of the iteration methods returns 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 == 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 }
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 }
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 }
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 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
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
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.
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
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
moment-range is UNLICENSED.
[4.0.2]
add
methodmoment.range()
without argumentsdiff
& duration
from rounded
to precise
to reflect the underlying moment methodmoment.range()
& DateRange
constructor
types to allow mixed Date
& Moment
parametersinterval
/unit
flow parameter types in the by
, diff
, duration
, reverseBy
& snapTo
to include all strings allowed by moment3.3.3333
2.24.0
2
add
and intersect
to DateRange | null
as opposed to DateRange | undefined
toDate()
method return type from an array of Date
s to a Date
tupleextendMoment()
typescript declaration to give access to moment namespace variables, e.g. moment.duration()
, moment.HTML5_FMT
FAQs
Fancy date ranges for Moment.js
The npm package moment-range receives a total of 272,162 weekly downloads. As such, moment-range popularity was classified as popular.
We found that moment-range demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.