Add Business Days Skipping Weekends

Move a UTC date forward or backward by business days while skipping weekends and an optional set of holiday date keys.

TypescriptData Integrity

Code

snippet
export function addBusinessDays(
  start: Date,
  days: number,
  holidays: ReadonlySet<string> = new Set(),
): Date {
  if (!(start instanceof Date) || Number.isNaN(start.getTime())) {
    throw new TypeError("start must be a valid Date");
  }
  if (!Number.isInteger(days)) throw new TypeError("days must be an integer");
  const result = new Date(start.getTime());
  let remaining = Math.abs(days);
  const step = days < 0 ? -1 : 1;
  while (remaining > 0) {
    result.setUTCDate(result.getUTCDate() + step);
    if (isBusinessDay(result, holidays)) remaining -= 1;
  }
  return result;
}

export function isBusinessDay(date: Date, holidays: ReadonlySet<string> = new Set()): boolean {
  if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
    throw new TypeError("date must be a valid Date");
  }
  const weekday = date.getUTCDay();
  if (weekday === 0 || weekday === 6) return false;
  return !holidays.has(toDateKey(date));
}

export function toDateKey(date: Date): string {
  return date.toISOString().slice(0, 10);
}

const holidays = new Set(["2026-12-25"]);
console.log(addBusinessDays(new Date("2026-12-24T12:00:00Z"), 1, holidays).toISOString());
console.log(addBusinessDays(new Date("2026-12-28T00:00:00Z"), -1, holidays).toISOString());
console.log(isBusinessDay(new Date("2026-10-24T00:00:00Z")));
console.log(addBusinessDays(new Date("2026-10-21T00:00:00Z"), 0).toISOString());