JavaScript Week Number
Safe ISO week helper
This dependency-free helper accepts a valid YYYY-MM-DD calendar date, with years 0001–9999. It returns the ISO week-year and week number separately and rejects impossible dates instead of silently rolling them forward.
function getIsoWeek(dateString) {
if (typeof dateString !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
throw new RangeError("Use a valid YYYY-MM-DD calendar date.");
}
const [year, month, day] = dateString.split("-").map(Number);
const date = new Date(0);
date.setUTCFullYear(year, month - 1, day);
if (year < 1 || date.getUTCFullYear() !== year ||
date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) {
throw new RangeError("Use a valid YYYY-MM-DD calendar date.");
}
// Thursday determines the ISO week-year, not the input's calendar year.
const weekday = date.getUTCDay() || 7;
date.setUTCDate(date.getUTCDate() + 4 - weekday);
const weekYear = date.getUTCFullYear();
const weekOne = new Date(0);
weekOne.setUTCFullYear(weekYear, 0, 4);
const weekOneDay = weekOne.getUTCDay() || 7;
weekOne.setUTCDate(weekOne.getUTCDate() + 1 - weekOneDay);
const weekNumber = Math.floor((date.getTime() - weekOne.getTime()) / 604800000) + 1;
return { weekYear, weekNumber };
} const result = getIsoWeek("2027-01-01");
console.log(result);
// { weekYear: 2026, weekNumber: 53 }
getIsoWeek("2027-01-04");
// { weekYear: 2027, weekNumber: 1 }
// getIsoWeek("2026-02-29") throws RangeError: 2026 is not a leap year. Safe date parsing
Here the input is a calendar date, not an instant. The helper uses UTC setters and getters only as a timezone-neutral way to do calendar arithmetic; it does not convert your date into another timezone.
JavaScript parses a date-only string such as "2027-01-01" as UTC. Reading that result with local getters can produce the previous date in timezones west of UTC. Do not mix local getters with UTC parsing.
The validation round-trip also catches values such as 2026-02-29 that date constructors may normalize. setUTCFullYear preserves years below 100 without the 1900-based adjustment made by Date.UTC.
Timezone warning
For current-week features, calculate the user's local calendar date first, then calculate the week number from that date.
Edge-case test table
| Input | Expected ISO week date | Monday–Sunday range |
|---|---|---|
2024-02-29 | 2024-W09-4 | 2024-02-26 to 2024-03-03 |
2025-12-29 | 2026-W01-1 | 2025-12-29 to 2026-01-04 |
2026-12-28 | 2026-W53-1 | 2026-12-28 to 2027-01-03 |
2027-01-01 | 2026-W53-5 | 2026-12-28 to 2027-01-03 |
2027-01-03 | 2026-W53-7 | 2026-12-28 to 2027-01-03 |
2027-01-04 | 2027-W01-1 | 2027-01-04 to 2027-01-10 |
Download and run the boundary tests
The JSON fixture contains 17 leap-day and New Year examples, including every date in 2026-W53. Expected fields include the week-year, week number, ISO weekday (Monday = 1), full ISO notation, and inclusive Monday–Sunday range.
Download ISO boundary examples (JSON), save the helper and test below as verify-weeks.mjs, and run node verify-weeks.mjs from that folder.
// Save the JSON download beside this file as:
// whatweek-iso-week-boundary-examples.json
// Add the getIsoWeek helper above, then run: node verify-weeks.mjs
import { readFile } from "node:fs/promises";
const fixture = JSON.parse(await readFile(
new URL("./whatweek-iso-week-boundary-examples.json", import.meta.url),
"utf8"
));
for (const expected of fixture.cases) {
const actual = getIsoWeek(expected.date);
if (actual.weekYear !== expected.weekYear || actual.weekNumber !== expected.weekNumber) {
throw new Error("ISO week mismatch for " + expected.date);
}
}
console.log(fixture.cases.length + " ISO week examples passed."); The sample runner checks the helper's two output fields. When testing a date-range implementation, also compare weekStarts and weekEnds against the fixture. The same dates are available as CSV and Excel formula examples.
API option
Use the WhatWeek API when you need stable JSON responses for applications or internal tools.
For the 2026–2027 transition, see Week 53, 2026 and the 2027 week-number calendar.
JavaScript date behavior: MDN Date reference and setUTCFullYear.