"Week 1 of 2026 starts on December 29, 2025."
If that sentence confused you, welcome to ISO week numbers — one of the most counterintuitive corners of date arithmetic.
What Is an ISO Week Number?
ISO 8601 defines a week as Monday to Sunday. Week 1 of a year is the week containing the year's first Thursday. This means:
- A year has either 52 or 53 ISO weeks
- The first days of January can belong to the previous year's last week
- The last days of December can belong to next year's first week
Real examples:
| Date | ISO Week | ISO Week Year |
|---|---|---|
| December 29, 2025 | Week 1 | 2026 |
| December 30, 2025 | Week 1 | 2026 |
| January 1, 2026 | Week 1 | 2026 |
| December 28, 2026 | Week 52 | 2026 |
| December 29, 2026 | Week 53 | 2026 |
| January 1, 2027 | Week 53 | 2026 |
Notice: January 1, 2027 belongs to ISO week 53 of 2026.
ISO Week vs US Week
The US system is different:
| Property | ISO 8601 | US (common) |
|---|---|---|
| First day of week | Monday | Sunday |
| Week 1 definition | Contains first Thursday | Contains January 1 |
| Week year can differ from calendar year | Yes | No |
This divergence causes real problems when you mix them. A US-style "week 1 of 2026" starts January 1. An ISO week 1 of 2026 starts December 29, 2025.
Calculating ISO Week Number in JavaScript
JavaScript's Date object has no built-in ISO week support. Here's a correct implementation:
function getISOWeek(date) {
const d = new Date(date);
// Move to nearest Thursday (ISO week is defined by Thursday)
d.setDate(d.getDate() + 4 - (d.getDay() || 7));
const yearStart = new Date(d.getFullYear(), 0, 1);
const weekNum = Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
return { week: weekNum, year: d.getFullYear() };
}
getISOWeek(new Date('2025-12-29')); // { week: 1, year: 2026 }
getISOWeek(new Date('2026-01-01')); // { week: 1, year: 2026 }
getISOWeek(new Date('2027-01-01')); // { week: 53, year: 2026 }
Note the return includes both week and year — because the ISO week year can differ from the calendar year.
The %V vs %W Format Code Trap
If you're formatting dates server-side, be careful with strftime format codes:
| Code | Meaning |
|---|---|
%V |
ISO week number (01-53), where week 1 has >=4 days in the new year |
%W |
Week number, where week 1 starts on the first Monday of the year |
%U |
Week number, where week 1 starts on the first Sunday of the year |
import datetime
d = datetime.date(2025, 12, 29)
print(d.strftime('%V')) # "01" (ISO week 1 of 2026)
print(d.strftime('%W')) # "52" (52nd Monday-starting week of 2025)
print(d.strftime('%G')) # "2026" (ISO week YEAR, not calendar year)
print(d.strftime('%Y')) # "2025" (calendar year)
Using %Y with %V is a common mistake — they belong to different systems. Always pair %G with %V.
Practical Uses of Week Numbers
Time tracking — Many companies report weekly hours using ISO week numbers. Mismatching ISO vs US weeks causes reporting discrepancies.
Retail planning — Fiscal calendars often use ISO weeks to ensure comparable year-over-year metrics (ISO weeks are always exactly 7 days, unlike months).
Agile sprints — Sprint identifiers often reference ISO weeks. If your team uses "W01" and another uses a US-style week 1, you're talking about different date ranges.
Database queries — PostgreSQL's EXTRACT(WEEK FROM date) returns ISO week numbers. MySQL's WEEK(date) returns US-style by default. Mixing these in a BI tool produces silent errors.
-- PostgreSQL: ISO week (Monday-based)
SELECT EXTRACT(ISODOW FROM '2025-12-29'::date); -- 1 (Monday)
SELECT EXTRACT(WEEK FROM '2025-12-29'::date); -- 1 (week 1 of 2026!)
-- MySQL: returns week of calendar year by default
SELECT WEEK('2025-12-29'); -- 52
SELECT WEEK('2025-12-29', 3); -- 1 (mode 3 = ISO)
Getting Week Boundaries
function getISOWeekBounds(date) {
const d = new Date(date);
const day = d.getDay() || 7; // Convert Sunday (0) to 7
const monday = new Date(d);
monday.setDate(d.getDate() - day + 1);
monday.setHours(0, 0, 0, 0);
const sunday = new Date(monday);
sunday.setDate(monday.getDate() + 6);
sunday.setHours(23, 59, 59, 999);
return { start: monday, end: sunday };
}
getISOWeekBounds(new Date('2026-01-01'));
// start: Mon Dec 29, 2025
// end: Sun Jan 4, 2026
For a quick lookup without writing code — what week number is today, and when does the current week start and end — datetimecalculator.app/week-number shows both ISO and calendar-week views.
Summary
- ISO weeks run Monday–Sunday; week 1 contains the year's first Thursday
- The ISO week year (
%G) can differ from the calendar year (%Y) — always pair them correctly - JavaScript has no built-in ISO week support; implement it or use a library
- PostgreSQL uses ISO by default; MySQL doesn't — watch out when mixing
Has a week number mismatch ever broken your analytics or reporting? The ISO vs US divergence seems to catch almost every team at least once.
Top comments (0)