date.isocalendar / fromisocalendar

ISO weeks start on Monday, and week 1 is the week containing the year's first Thursday. So the ISO year can differ from the calendar year for a few days around New Year.

date methodPython 2.3+ (named tuple 3.9+, fromisocalendar 3.8+)Live demo
Common call
d.isocalendar().week
Returns
40 for 2026-09-29
Replaces
int(d.strftime('%V')) and hand-written week logic
Watch out
Use .year from isocalendar() with .week, not d.year
d.isocalendar()
→ IsoCalendarDate

Demo

Live evaluation
Try dates near New Year: the ISO year and the calendar year part ways.
Try:
Inputs
whenstrYYYY-MM-DD
Code
from datetime import date
d = date.fromisoformat('2026-09-29')
(d.year, d.isocalendar())
Result
(2026, datetime.IsoCalendarDate(year=2026, week=40, weekday=2))

1 January 2027 is a Friday, so it still belongs to the last ISO week of 2026 (week 53), while Monday 29 December 2025 already starts 2026-W01. 2026 has 53 ISO weeks because it begins on a Thursday; 2025 has only 52.

Parameters

NameTypeRequiredDescription
yearintyesfromisocalendar: the ISO year, 1..9999.
weekintyesfromisocalendar: 1..52, or 53 in long ISO years.
dayintyesfromisocalendar: 1 (Monday) .. 7 (Sunday).

Return value

IsoCalendarDate — A named tuple (year, week, weekday) — weekday 1 = Monday. fromisocalendar returns a date.

Common patterns

Group by ISO week
Key on (ISO year, week) — never (calendar year, week).
key = d.isocalendar()[:2]  # (year, week)
Monday of an ISO week
fromisocalendar with day 1.
from datetime import date
week_start = date.fromisocalendar(2026, 40, 1)

Examples

1. Named tuple (3.9+)
from datetime import date date(2026, 9, 29).isocalendar()
Returns
datetime.IsoCalendarDate(year=2026, week=40, weekday=2)
2. Access by name
from datetime import date date(2026, 9, 29).isocalendar().week
Returns
40
3. It is still a tuple
from datetime import date tuple(date(2026, 9, 29).isocalendar())
Returns
(2026, 40, 2)
4. New Year in the old ISO year
from datetime import date date(2027, 1, 1).isocalendar()
Returns
datetime.IsoCalendarDate(year=2026, week=53, weekday=5)
5. Back to a date
from datetime import date date.fromisocalendar(2026, 40, 2)
Returns
datetime.date(2026, 9, 29)
6. Week 1 can start in December
from datetime import date date.fromisocalendar(2026, 1, 1)
Returns
datetime.date(2025, 12, 29)
7. Validation
from datetime import date date.fromisocalendar(2025, 53, 1)
Returns
ValueError: Invalid week: 53

Pitfalls

1. Pairing the ISO week with the calendar year
Around New Year the week belongs to the other year. Take the year from isocalendar() too.
d.year + week
from datetime import date
d = date(2025, 12, 29)
(d.year, d.isocalendar().week)
(2025, 1)
ISO year + week
from datetime import date
d = date(2025, 12, 29)
d.isocalendar()[:2]
(2026, 1)
2. Zero-based weekday
fromisocalendar uses ISO weekdays 1..7, not weekday()'s 0..6.
day 0
from datetime import date
date.fromisocalendar(2026, 1, 0)
ValueError: Invalid day: 0 (range is [1, 7])
day 1 = Monday
from datetime import date
date.fromisocalendar(2026, 1, 1)
datetime.date(2025, 12, 29)

When to use

Use it
  • Weekly reports, sprints and payroll periods
  • Parsing and writing YYYY-Www-D week dates
Reach for something else
  • US-style weeks starting on Sunday → strftime %U
  • Calendar months → date fields

Notes

CPython impl
iso_week1_monday / iso_to_ymd in Modules/_datetimemodule.c; fromisocalendar validates year, then week, then day
Week 53
A year has 53 ISO weeks when it starts on a Thursday, or on a Wednesday in a leap year
Inherited
datetime.isocalendar and datetime.fromisocalendar (midnight) are the same methods
History
isocalendar returned a plain tuple before 3.9; fromisocalendar was added in 3.8

FAQ

d.isocalendar().week for the ISO 8601 week (Monday start, week 1 contains the first Thursday). strftime("%U") and "%W" give other, non-ISO week numbers.