DEV Community

HAU
HAU

Posted on

ISO Week Numbers: Why January 1st Is Sometimes in Week 53

"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 }
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)