Interval Operations
GMT’s interval functions cover containment, overlap, set operations, splitting, counting, and length. The 10 mistakes here are the ones that have caused the most confusion.
Mistakes
Section titled “Mistakes”Confusing intervalsOverlap with intervalAbuts
intervalsOverlap returns true when two intervals share any instants. intervalAbuts returns true when they touch at exactly one endpoint without overlapping. Touching is not overlapping.
Wrong
intervalsOverlapDate("2024-03-15/2024-03-20", "2024-03-20/2024-03-25"); // false — they abut, not overlapRight
import { intervalsOverlapDate, intervalAbutsDate } from "@northguild/gmt/interval";
intervalsOverlapDate("2024-03-15/2024-03-20", "2024-03-20/2024-03-25"); // false
intervalAbutsDate("2024-03-15/2024-03-20", "2024-03-20/2024-03-25"); // trueAssuming intervalEngulfs is new logic
intervalEngulfs returns true when the first interval completely contains the second. It is not the same as overlap — A can overlap B without engulfing it.
Wrong
// assuming overlap implies engulfingRight
import { intervalEngulfsDate, intervalsOverlapDate } from "@northguild/gmt/interval";
intervalsOverlapDate("2024-03-10/2024-03-20", "2024-03-15/2024-03-18"); // true
intervalEngulfsDate("2024-03-10/2024-03-20", "2024-03-15/2024-03-18"); // true — B is inside AMutating intersection/union results
intervalIntersection and intervalUnion return new interval objects. The originals are unchanged. Mutating the result does not affect the inputs, but mutating the inputs before calling does.
Wrong
const a = { start: "2024-03-15", end: "2024-03-20" };
const b = { start: "2024-03-18", end: "2024-03-25" };
const r = intervalIntersectionDate(a, b);
a.end = "2024-03-22"; // does not change rRight
const r = intervalIntersectionDate(a, b);
// r is independent — safe to use after the callOff-by-one on splitIntervalByUnit final slice
splitIntervalByUnitDate splits an interval into N equal pieces. The final slice may be shorter than the others if the interval is not evenly divisible. The number of slices is ceiling(duration / unit), not floor.
Wrong
splitIntervalByUnitDate("2024-03-15/2024-03-20", "day"); // 6 slices
// assuming all slices are exactly 1 dayRight
// the last slice is the remainder — 2024-03-19 to 2024-03-20 is 1 day, which matches
// but for uneven splits, expect a shorter final sliceUsing intervalCount where you meant a duration
intervalCountDate returns how many full unit-sized intervals fit inside a range. It is not the duration of the interval. If you need '5 days', use intervalLengthDate or diffDateAsDuration.
Wrong
intervalCountDate("2024-03-15/2024-03-20", "day"); // 5 — number of full days
// used as the duration — but duration and count are different conceptsRight
import { intervalLengthDate, diffDateAsDuration } from "@northguild/gmt";
intervalLengthDate("2024-03-15/2024-03-20", "day"); // 5 — duration in days
diffDateAsDuration("2024-03-15", "2024-03-20"); // duration objectExpecting a zero-length interval to count 1
An interval where start === end has zero duration. intervalCountDate returns 0 for it, not 1. A zero-length interval is empty, not a single instant.
Wrong
intervalCountDate("2024-03-15/2024-03-15", "day"); // 0 — not 1Right
// a zero-duration interval is empty
// use a single point representation if you need to express "just this instant"Assuming intervalFromDurationTime applies a calendar-unit duration
intervalFromDurationDate creates an interval from a start date and a duration. Calendar-unit durations (years, months) require a reference point to resolve to days. Without one, the interval length is ambiguous.
Wrong
intervalFromDurationDate("2024-03-15", "P1M"); // 30 or 31 days depending on implicit referenceRight
import { intervalFromDurationDate } from "@northguild/gmt/interval";
intervalFromDurationDate("2024-03-15", "P1M", { relativeTo: "2024-03-15" });
// "2024-03-15/2024-04-15" — resolved using the referenceForgetting a negative duration can invert the span
Subtracting a larger duration than the interval width produces a negative result. intervalFromDurationDate with a negative duration creates an interval where end < start.
Wrong
intervalFromDurationDate("2024-03-15", "P-10D"); // end before start — invalid intervalRight
// ensure the duration is positive, or normalize the bounds after constructionExpecting date-fns's getOverlappingDaysInIntervals number from intervalOverlappingDays*
date-fns's getOverlappingDaysInIntervals returns the count of overlapping days. GMT's intervalOverlappingDaysDate returns the overlapping interval object(s). They have different return types and different semantics for edge cases.
Wrong
// expecting a number like date-fnsRight
import { intervalOverlappingDaysDate } from "@northguild/gmt/interval";
// returns the overlapping sub-interval, not a day countConfusing intervalLength with intervalCount
intervalLengthDate returns the duration of an interval in a given unit. intervalCountDate returns how many full unit-sized intervals fit inside. They are not the same when the interval is not evenly divisible.
Wrong
intervalLengthDate("2024-03-15/2024-03-20", "day"); // 5 — the length
intervalCountDate("2024-03-15/2024-03-20", "day"); // 5 — count of full days
// these happen to match here, but not for uneven intervalsRight
// use intervalLengthDate when you need the span
// use intervalCountDate when you need how many complete units fitExpecting intervalXorAll/mergeIntervals to take flat arguments like their pairwise siblings
intervalXorAll and mergeIntervals accept an array of intervals, not individual arguments. Passing two intervals as separate arguments like intervalXorDate produces a type mismatch.
Wrong
intervalXorDate(a, b); // pairwise — correct for 2 intervals
intervalXorAll(a, b); // wrong — expects an arrayRight
import { intervalXorAll, mergeIntervalsDate } from "@northguild/gmt/interval";
intervalXorAll([a, b, c]); // array of 3+ intervals — correctSee also
Section titled “See also”- Intervals guide
intervalsOverlapDatereferenceintervalAbutsDatereferenceintervalEngulfsDatereferenceintervalIntersectionDatereferenceintervalFromDurationDatereferenceintervalCountDatereferenceintervalLengthDatereferencesplitIntervalByUnitDatereferencemergeIntervalsDatereferenceintervalXorAllDatereference