Skip to content
VersionSize

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 to 1).
    • latest: If true, returns the dates from newest to oldest (defaults to false).

Returns

  • An array of Date objects 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 TypeError if input dates are invalid.

See Also

  • expires: Check if a date has passed.
  • timeDiff: Calculate the duration between two dates.