Get the ISO week number of the year
Print which calendar week a date falls into — for sprint planning ("we are in W20"), retention dashboards (weekly bucketing), payroll periods, and any time-series workflow that wants "year-week" as a stable key.
How to get the iso week number of the year in each shell
date -d "2026-05-17" +%V`+%V` is ISO 8601 week number (01–53). ISO week starts on Monday; week 01 is the week containing the year's first Thursday. `+%U` is Sunday-start week (00–53, used in the USA — Jan 1 always falls in week 0 or 1). `+%W` is Monday-start but POSIX-flavoured — first Monday of year is the start of week 01 (so dates before it land in week 00). Use `+%V` for international/ISO compliance, `+%U` for US-context dashboards.
date -d "2026-05-17" +%Vdate -d "2026-05-17" +%V[System.Globalization.ISOWeek]::GetWeekOfYear((Get-Date "2026-05-17"))`[System.Globalization.ISOWeek]` (.NET Core 3.0+ / pwsh 7+) is the right ISO-8601 abstraction — returns 1–53, Monday-start, Thursday-rule. pwsh 5.1 / Windows PowerShell: fall back to `(Get-Culture).Calendar.GetWeekOfYear((Get-Date), [System.Globalization.CalendarWeekRule]::FirstFourDayWeek, [System.DayOfWeek]::Monday)`. To also get the ISO year (which DIFFERS from calendar year around Dec 28 – Jan 4): `[ISOWeek]::GetYear($date)`.
powershell -NoProfile -Command "[ISOWeek]::GetWeekOfYear((Get-Date '2026-05-17'))"No native cmd. Shelling to pwsh + `[ISOWeek]` is the practical answer. Older systems without pwsh 7: use the verbose `(Get-Culture).Calendar...` form via `powershell -Command` (Windows 10+ ships pwsh 5.1).
Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.
Gotchas & notes
- **The year-end boundary is the gotcha that breaks reports** — ISO week 01 is the week containing the year's first Thursday. So **December 31** can be in **W01 of the NEXT year**, and **January 1** can be in **W52 or W53 of the PREVIOUS year**. Concrete: `2026-01-01` is a Thursday → it's in `2026-W01`; but `2027-01-01` is a Friday → it's in `2026-W53`. Always use ISO-week-year (`%G`) paired with ISO-week (`%V`) — NEVER plain year `%Y` with `%V`. `%G-W%V` gives `2026-W53` for `2027-01-01` (correct); `%Y-W%V` gives `2027-W53` (WRONG — there is no week 53 of 2027 in ISO). pwsh: pair `[ISOWeek]::GetYear($d)` with `[ISOWeek]::GetWeekOfYear($d)`.
- **Sunday-start vs Monday-start vs ISO — three competing conventions, all live in production**. USA, Canada, parts of Latin America: week starts SUNDAY (`%U`); Excel's default is Sunday-start. Europe, ISO 8601, most enterprise software: Monday-start. The Middle East historically: Saturday-start. `%V` is internationally-correct; `%U` and `%W` are convenient for matching legacy US reports. Mixing them is the bug source — a "this is week N" metric from one team's `%U` shifts by 0–7 days when compared against another team's `%V`. Pick ONE per codebase and call it out in docs.
- **Weeks 53 exist some years, not others** — ISO years have 53 weeks if the year starts on a Thursday, OR if it's a leap year that starts on a Wednesday. Examples: 2009, 2015, 2020, 2026, 2032 all have 53 ISO weeks. Most years have 52. Code that does `for w in 1..52` for weekly aggregation MISSES week 53 every 5-7 years, dropping data. The right loop bounds: `for w in 1..([ISOWeek]::GetWeeksInYear($year))` (pwsh) or `for w in $(seq 1 $(date -d "$year-12-28" +%V))` (bash — Dec 28 is always in the last ISO week of the year, so its week number IS the year's week count). Skipping this nuance is the cause of "missing week 53 of 2020" bugs in COVID retros.
- **Week-of-month, week-of-quarter — not built into `date`**. `+%V` only does week-of-YEAR. For week-of-month: `echo $(( ($(date -d "2026-05-17" +%-d) - 1) / 7 + 1 ))` (the `+%-d` strips leading zero; some BSD `date` doesn't support `-d` flag — use `%d` and live with `09` style). pwsh: `[math]::Ceiling((Get-Date).Day / 7)`. For "week-of-quarter": `(((Get-Date).Month - 1) % 3) * 4 + WeekOfMonth` is approximate; precise quarterly bucketing needs calendar libraries (`pandas` periods, `python-dateutil.rrule`) — DIY in shell becomes a rat's nest of edge cases (months with 4 vs 5 weeks, quarters that span ISO-year boundaries).
- **Cross-platform week number — Python is the cleanest portable option**: `python3 -c "from datetime import date; iso = date(2026,5,17).isocalendar(); print(f'{iso.year}-W{iso.week:02d}')"` outputs `2026-W20` correctly handling year-boundary. Available everywhere Python 3 ships, which is essentially every modern Linux + macOS + Windows-via-Microsoft-Store. For pipeline scripts that must run on a "minimal" container (alpine without coreutils): `busybox date` only supports `%V` if BusyBox was compiled with `BUSYBOX_DATE_FANCY_OPTS`, which alpine's default `apk add busybox-extras` may or may not include — `python3` (`apk add python3 ~13 MB`) is a more reliable add than fighting BusyBox configure flags.
Related commands
Related tasks
- Get the day of the week for a date— Print which weekday a given date falls on — for backup-window scripts ("only run on Sunday"), log rotation, conditional CI gates ("skip the weekly job on Friday"), or `cron` replacements that need day-of-week introspection.
- Calculate days between two dates— Compute the integer number of days between two calendar dates — for SLA timers, log-window queries, license-expiry math, or backfill scripts that ask "how many days have passed since X?".
- Parse a relative date like "next Friday" or "2 weeks ago"— Convert a human-readable relative-time expression ("3 days ago", "next Monday", "last quarter end") into an absolute date — for log filters, backfill ranges, scheduling, or any script that wants to accept user input the same way GitHub Actions cron does.