ISO Week Number and Week Start Date

Calculate ISO 8601 week numbers and convert a year plus week back to the Monday that starts it, with round-trip validation.

JavascriptData Integrity

Code

snippet
export function isoWeek(date = new Date()) {
  const value = toUtcDate(date);
  const thursday = new Date(value.getTime());
  const weekday = value.getUTCDay() || 7;
  thursday.setUTCDate(value.getUTCDate() + 4 - weekday);
  const year = thursday.getUTCFullYear();
  const firstThursday = new Date(Date.UTC(year, 0, 4));
  const offset = firstThursday.getUTCDay() || 7;
  firstThursday.setUTCDate(firstThursday.getUTCDate() + 4 - offset);
  const week = 1 + Math.round((thursday - firstThursday) / (7 * 24 * 60 * 60 * 1000));
  return { year, week };
}

export function isoWeekStart(year, week) {
  if (!Number.isInteger(year) || year < 1 || year > 9999) throw new RangeError("year out of range");
  if (!Number.isInteger(week) || week < 1 || week > 53) throw new RangeError("week out of range");
  const januaryFourth = new Date(Date.UTC(year, 0, 4));
  const weekday = januaryFourth.getUTCDay() || 7;
  const monday = new Date(januaryFourth.getTime());
  monday.setUTCDate(januaryFourth.getUTCDate() - weekday + 1 + (week - 1) * 7);
  const check = isoWeek(monday);
  if (check.year !== year || check.week !== week) {
    throw new RangeError("week does not exist in that ISO year");
  }
  return monday;
}

function toUtcDate(date) {
  if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
    throw new TypeError("date must be a valid Date");
  }
  return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
}

const week = isoWeek(new Date("2026-01-01T00:00:00Z"));
console.log(week);
console.log(isoWeekStart(week.year, week.week).toISOString().slice(0, 10));
console.log(isoWeek(new Date("2024-12-30T00:00:00Z")));