Purpose
"Week 29" means at least four different things depending on which week system produced the number. This page catalogs the competing conventions this KB has to interoperate with, states which one it standardizes on, and gives the crosswalk logic for translating between them.
The competing systems
- ISO-8601
- Monday start. Week 1 is the week containing the year's first Thursday (equivalently, the week containing January 4). Years have 52 or 53 weeks. Used by: this KB, most of Europe, ISO-conformant systems generally.
- US / retail (NRF 4-5-4)
- Sunday start. The National Retail Federation's 4-5-4 fiscal calendar groups weeks into quarters of 4, 5, and 4 weeks (13 weeks/quarter), with its own fiscal year start (often the Sunday closest to Jan 31 or Feb 1), not the Gregorian calendar.
- Broadcast / Nielsen
- Monday start, like ISO, but organized into its own broadcast month and quarter — a broadcast month is a whole number of broadcast weeks (typically 4 or 5) and does not align to the Gregorian month; a broadcast quarter runs 13 or 14 weeks. See broadcast-calendar-month below.
- Middle East
- Common convention starts the week on Saturday (some countries: Sunday), reflecting a Friday-Saturday or Friday-only weekend. Week numbering under this convention does not agree with ISO week boundaries.
A single instant can therefore carry a different week number under each system, and even systems that agree on the start day (ISO and broadcast both start Monday) can still disagree on which week is "week 1" of the year, because their year boundaries and roll-up rules differ.
This KB's standard: ISO for the canonical key
This knowledge base standardizes on ISO-8601 for the (isoYear, isoWeek, slot) key used everywhere — see ISO Week and
The 168 Axis. ISO was chosen because it is
parameter-free and exact (no declared cutover, no fiscal-year anchor to
configure) and because its Monday start aligns naturally with slot 0 =
Monday 00:00 UTC. Any other week system a downstream platform reports in
(US/retail, broadcast) is treated as a presentation crosswalk applied on
top of the canonical ISO key, not as an alternate canonical grain.
Crosswalk logic
import { isoWeekOf } from "@/lib/time/isoweek";
import { DateTime } from "luxon";
// ISO week (this KB's canonical): Monday start.
const iso = isoWeekOf(Date.parse("2026-07-19T00:00:00Z")); // a Sunday
// -> { isoYear: 2026, isoWeek: 29, isoWeekday: 7 }
// US/retail week number (Sunday start) for the SAME instant requires a
// different anchor rule entirely — it is not a fixed offset from the ISO
// week, because the two systems' "week 1" definitions diverge independently
// each year. A retail crosswalk must be computed against the retailer's own
// declared fiscal calendar, not derived from the ISO week number.
const dt = DateTime.fromMillis(Date.parse("2026-07-19T00:00:00Z"), { zone: "utc" });
const sundayStartWeekday = dt.weekday % 7; // 0 = Sunday ... 6 = Saturday
The critical point the snippet makes explicit: because ISO and US/retail weeks can start their year in different places (ISO week 1 anchors to the first Thursday; a retail fiscal year anchors to a declared date near month-end), there is no universal arithmetic formula converting an ISO week number directly into a retail week number — the retailer's specific fiscal calendar (its declared year-start date) must be consulted. The only safe general crosswalk is instant-based: resolve the target instant, then apply each system's own rule to that instant independently, rather than transforming one week number into another.
Why a bare week number is a bug
A payload containing only "week": 29 cannot be interpreted correctly by
any receiving system without also knowing which week system produced it —
ISO week 29 of 2026 (Jul 13-19), a US/retail week 29 (a different date
range, anchored to that retailer's fiscal year start), and a broadcast week
29 (aligned to Nielsen's broadcast calendar) are three different seven-day
spans that happen to share a number. Always pair a week number with its
system, and prefer the full (isoYear, isoWeek) pair — or the combined
week_slot_key — as the canonical join key.
Edge cases
Week-numbering systems is this page's core subject. Broadcast calendar month: because a broadcast month is a whole number of broadcast weeks rather than a Gregorian month, reconciling broadcast-month reporting against calendar-month reporting requires a declared week-to-month crosswalk, not a date-range assumption — see Broadcast Day for the related per-day convention. Week-year boundary and fifty-three-week years are properties of the ISO system specifically and are detailed on the ISO Week page.
Python parity
from datetime import datetime, timezone
def iso_week(epoch_ms: int) -> tuple[int, int, int]:
return datetime.fromtimestamp(epoch_ms / 1000, tz=timezone.utc).isocalendar()
def sunday_start_weekday(epoch_ms: int) -> int:
# 0 = Sunday ... 6 = Saturday, for building a US/retail-style crosswalk.
dt = datetime.fromtimestamp(epoch_ms / 1000, tz=timezone.utc)
return (dt.isoweekday()) % 7
Python's isocalendar() gives the ISO figures natively; a US/retail or
broadcast crosswalk still requires each system's own declared calendar (a
retailer's 4-5-4 fiscal year, or Nielsen's broadcast calendar) as external
input — no standard library or package encodes those rules generically,
since they are business conventions, not international standards.
