moment-range
Fancy date ranges for Moment.js — create, query, compare, and iterate over time intervals.
Repository Health
Technical Analysis
moment-range extends Moment.js with a DateRange type and a set of methods for working with spans of time rather than single points in time. It lets you build a range from two dates, an array, an ISO 8601 time interval string, or a named interval like month or year, then query it for containment, overlap, adjacency, intersection, and difference.
Beyond comparisons, moment-range adds iteration: by and byRange walk a range in fixed steps (every day, every 3 hours, every custom duration), while reverseBy and reverseByRange do the same from the end backwards. Ranges also support set-like operations — add to merge overlapping ranges, subtract to remove one range from another, and snapTo to round a range’s edges out to the nearest interval boundary.
The library ships as a small ES6 class (DateRange) plus a moment.range() factory function attached via extendMoment(moment), so it stays an opt-in extension rather than a Moment.js fork. TypeScript and Flow type definitions are bundled, and a moment.isRange() helper and Moment#within() instance method round out the API for everyday date-range checks.
What You Get
- A
DateRangeclass supporting construction from two dates, an array, an ISO 8601 interval string, or a named interval (year,month,week, etc.) - Query methods —
contains,overlaps,intersect,adjacent,isEqual— for comparing ranges and points against a range - Iteration methods —
by,byRange,reverseBy,reverseByRange— that walk a range in fixed steps using native JS iterators - Set-like operations —
addto merge overlapping ranges,subtractto remove a range from another,snapToto round edges to interval boundaries - Bundled TypeScript (
.d.ts) and Flow (.js.flow) type declarations for type-checked consumption
Common Use Cases
- Checking whether a given date or timestamp falls inside a booking, subscription, or availability window
- Detecting overlapping or adjacent date ranges — e.g. conflicting calendar events or reservation periods
- Generating a list of dates/timestamps at a fixed cadence within a window, such as every day or every hour between a start and end
- Computing the intersection or difference between two ranges, e.g. the overlapping portion of two employees’ shifts
- Building calendar or scheduling UIs that need to render, compare, and step through spans of time rather than single dates
Under The Hood
Architecture
The entire library lives in one module, lib/moment-range.js, structured around a single DateRange ES6 class plus an extendMoment(moment) function that mixes range-aware statics and instance methods onto a caller-supplied Moment.js instance. DateRange’s constructor normalizes several input shapes (two arguments, a two-element array, or an ISO interval string) into start/end Moment objects, defaulting to the library’s own effectively-infinite sentinel timestamps for open-ended ranges. Every comparison and set operation (contains, intersect, overlaps, subtract, adjacent) is implemented as pure numeric comparisons against .valueOf() millisecond timestamps rather than repeated Moment method calls, which keeps the core logic simple and testable in isolation from Moment’s own API surface. Iteration (by/byRange and their reverse variants) is implemented against the native Symbol.iterator protocol (via the es6-symbol polyfill dependency) so ranges can be consumed directly with for...of or spread syntax; nothing else in the app would break if this abstraction changed, since extendMoment is the sole integration seam with consumer code.
Tech Stack
The library targets Moment.js (>= 2) as a peer dependency and depends only on es6-symbol at runtime for iterator-protocol support in older environments. Source is written in ES6/Flow-annotated JavaScript and compiled with Babel (babel-preset-es2015, babel-preset-stage-0) and bundled for distribution with Webpack 2. The published dist/ output includes a UMD-style browser bundle alongside the CommonJS build, and both Flow (flow-bin) and TypeScript (tsc against a typing-tests/ project) type-check the bundled declaration files as part of the pre-release check script.
Code Quality
Tests are written with Mocha-style describe/it blocks (via expect.js assertions) and run in real browsers through Karma with the PhantomJS and Chrome launchers; the single test file covers the full public API — constructors, all query/iteration/set methods, edge cases like zero-length and open-ended ranges — in over 1,300 lines, which is extensive for a library this size. Code style is enforced with a project ESLint config (babel-eslint parser) run via yarn lint, and the preversion script chains type-checking, linting, and the test suite before any release, indicating a deliberate quality gate rather than ad hoc publishing. Error handling is minimal by design — the library throws only for explicitly invalid dates in rangeFromInterval and otherwise relies on Moment.js’s own permissive parsing.
What Makes It Unique
Rather than inventing a parallel date API, moment-range’s distinguishing choice is making ranges iterable via the standard JS iterator protocol, so a range can be looped with for...of or spread into an array using ordinary language syntax instead of a bespoke .toArray()-style method. Combining that with symmetric forward/backward iteration (by/reverseBy) and interval-based iteration by duration (byRange, using another Moment/duration object as the step rather than a named unit) gives it flexibility most simpler date-range helpers don’t attempt, though the underlying comparison logic itself uses standard interval-arithmetic patterns rather than a genuinely novel algorithm.
Used by 2 apps in this directory
Bigcapital
Invoicing Finance
Self-hostable double-entry accounting platform with invoicing, inventory, multi-currency, and real-time financial reporting for small and medium businesses.
Kestra
Devops · Data Engineering · Automation
Event-driven orchestration platform for data, AI, and infrastructure workflows — define everything in YAML, run anywhere at scale.