interval
The interval utility creates an array of dates between a start and end date, separated by a specified time unit (e.g., days, weeks, months). It's ideal for generating date series for calendars, charts, or timelines.
Implementation
View Source Code
ts
import { assert } from '../function/assert';
import { isDate } from '../typed/isDate';
// #region IntervalTypes
type IntervalType = 'D' | 'W' | 'M' | 'MS' | 'ME' | 'Y' | 'YS' | 'YE';
type IntervalOptions = {
interval?: IntervalType;
steps?: number;
latest?: boolean;
};
// #endregion IntervalTypes
/**
* Generates an array of dates between a start and end date, with a specified interval and step size.
*
* @example
* ```ts
* const options = { interval: 'D', steps: 1, latest: false };
*
* interval('2022-01-01', '2022-01-31', options); // Returns an array of dates for every day in January 2022
* ```
*
* @param start - The start date (Date object or ISO string).
* @param end - The end date (Date object or ISO string).
* @param options - Options for an interval and steps.
*
* @returns An array of generated dates.
*/
export function interval(
start: Date | string,
end: Date | string,
{ interval = 'D', steps = 1, latest = false }: IntervalOptions = {},
): Date[] {
const startDate = new Date(start);
const endDate = new Date(end);
assert([isDate(startDate), isDate(endDate)], 'Invalid date format. Use a valid Date object or ISO string.', {
args: { end, start },
type: TypeError,
});
const dateArray: Date[] = [];
let currentDate = new Date(incrementDate(startDate, interval, 0));
while (currentDate <= endDate) {
dateArray.push(currentDate);
currentDate = new Date(incrementDate(currentDate, interval, steps));
}
if (latest && dateArray.length > 0 && dateArray[dateArray.length - 1] < endDate) {
dateArray.push(endDate);
}
return dateArray;
}
function incrementDate(date: Date, interval: IntervalType, steps: number): Date {
const year = date.getFullYear();
const month = date.getMonth();
const day = date.getDate();
switch (interval) {
case 'D':
return new Date(Date.UTC(year, month, day + steps));
case 'W':
return new Date(Date.UTC(year, month, day + 7 * steps));
case 'M':
return new Date(Date.UTC(year, month + steps, day));
case 'MS':
return new Date(Date.UTC(year, month + steps, 1));
case 'ME':
return new Date(Date.UTC(year, month + steps + 1, 0));
case 'Y':
return new Date(Date.UTC(year + steps, month, day));
case 'YS':
return new Date(Date.UTC(year + steps, 0, 1));
case 'YE':
return new Date(Date.UTC(year + steps, 11, 31));
}
}Features
- Isomorphic: Works in both Browser and Node.js.
- Multiple Units: Supports days, weeks, months (start/end), and years (start/end).
- Customizable Steps: Control the density of the generated range.
- Directional Control: Option to return results in reverse chronological order.
API
Type Definitions
ts
type IntervalType = 'D' | 'W' | 'M' | 'MS' | 'ME' | 'Y' | 'YS' | 'YE';
type IntervalOptions = {
interval?: IntervalType;
steps?: number;
latest?: boolean;
};ts
function interval(start: Date | string, end: Date | string, options?: IntervalOptions): Date[];Parameters
start: The beginning of the date range.end: The end of the date range.options: Optional configuration:interval: The time unit ('D'=day, 'W'=week, 'M'=month, 'MS'=month start, 'ME'=month end, 'Y'=year, 'YS'=year start, 'YE'=year end; defaults to'D').steps: Number of units between each date (defaults to1).latest: Iftrue, returns the dates from newest to oldest (defaults tofalse).
Returns
- An array of
Dateobjects representing the generated sequence.
Examples
Daily Sequence
ts
import { interval } from '@vielzeug/toolkit';
// Generate 5 consecutive days
const days = interval('2024-01-01', '2024-01-05');
// [Jan 1, Jan 2, Jan 3, Jan 4, Jan 5]Weekly Steps (Reverse)
ts
import { interval } from '@vielzeug/toolkit';
const weeks = interval('2024-01-01', '2024-02-01', {
interval: 'W',
steps: 2,
latest: true,
});
// [Jan 29, Jan 15, Jan 1]Implementation Notes
- Performance-optimized for large date ranges.
- Correctly handles leap years and different month lengths.
- Throws
TypeErrorif input dates are invalid.