When a report supplies an ISO year, week number and weekday, validate that tuple with date.fromisocalendar(). A range check that merely allows weeks 1 through 53 is insufficient: the requested ISO year might not have week 53. Keep the ISO year with the week instead of substituting the resulting date's calendar year.
This matters near New Year. In the executable examples below, ISO 2020-W53-5 becomes calendar date 2021-01-01, while ISO 2025-W01-1 becomes 2024-12-30. Neither result is an off-by-one-year error. A weekly aggregation can become wrong if its key combines the calendar year with an ISO week number.
Validate the complete structured input
This block accepts integer fields, converts valid tuples, and checks the inverse mapping. It also demonstrates rejection of a nonexistent week 53, out-of-range weeks and out-of-range weekdays. All failures happen before a caller imports or stores the record.
from datetime import date
valid = [
((2020, 53, 5), '2021-01-01'),
((2025, 1, 1), '2024-12-30'),
]
for fields, expected in valid:
result = date.fromisocalendar(*fields)
assert result.isoformat() == expected
assert tuple(result.isocalendar()) == fields
print(fields, '->', result)
invalid = [(2021, 53, 1), (2025, 0, 1), (2025, 54, 1),
(2025, 1, 0), (2025, 1, 8)]
for fields in invalid:
try:
date.fromisocalendar(*fields)
except ValueError:
print('Rejected:', fields)
else:
raise AssertionError(('Unexpected acceptance', fields))
iso_year, week, weekday = date(2021, 1, 1).isocalendar()
assert (iso_year, week, weekday) == (2020, 53, 5)
print('Weekly key:', (iso_year, week))Use (iso_year, week) for an ISO weekly key. Retain the weekday too when the input identifies a particular day. The fixture was run on local Python 3.11.6, 3.13.2 and 3.14.3; it does not promise that a database, spreadsheet or external reporting tool uses the same week convention.
Distinguish an old parser symptom from current behavior
A historical CPython issue reports an invalid ISO week being normalized into another year by strptime. Testing the exact symptom gives a more useful diagnosis than treating it as a universal current bug. The next block records either the parsed date and round-trip fields or the actual exception. Both paths are deliberate; it should run successfully on the three tested runtimes.
from datetime import datetime
text = '2021-53-1'
try:
result = datetime.strptime(text, '%G-%V-%u').date()
except ValueError as error:
print(type(error).__name__, str(error))
else:
print('Parsed:', result)
print('Round trip:', tuple(result.isocalendar()))
assert tuple(result.isocalendar()) != (2021, 53, 1)
for text, pattern in [('2020-53-5', '%Y-%V-%u'),
('2020-53', '%G-%V')]:
try:
datetime.strptime(text, pattern)
except ValueError:
print('Incomplete or incompatible format rejected:', pattern)
else:
raise AssertionError(('Expected format rejection', pattern))Local Python 3.11.6 produced 2022-01-03 and round-trip tuple (2022, 1, 1) for the invalid input. Local Python 3.13.2 and 3.14.3 raised ValueError instead. These are observations of those installations. They do not identify the first fixed release or establish the behavior of every patch version. The invalid input must still be rejected by the import contract, regardless of which symptom a particular runtime exposes.
State the text format separately
For ISO week text parsed with strptime, the relevant directives are %G, %V and %u. The year is the ISO year. Mixing %Y with the ISO week or omitting a weekday is a different error from supplying a nonexistent week 53. The second half of the block makes those errors visible without matching fragile exception wording.
If your UI requires exactly YYYY-Www-d, define that spelling rule before conversion. A structured-date constructor validates calendar meaning; it does not validate arbitrary UI text. Likewise, accepting a flexible parser's input does not prove it obeyed the precise spelling required by an API. Validate text shape, extract integer fields, then pass those fields to the calendar validator. Keep a clear error for the original record rather than silently rewriting its week into a new one.
Verify the upstream week convention
Ask what the upstream label means before changing code. ISO weeks, Sunday-based weeks and Monday-based non-ISO weeks are different grouping contracts. Replacing one with another can shift records while making an error message disappear. Use known year-boundary fixtures agreed with the producer to verify both the input and the output grouping.
The reader problem here comes from a 2022 CPython report. That historical evidence supports this validation scenario, not current search volume or revenue. This article addresses week tuples and aggregation keys. If the actual input is only a month and day, the yearless February 29 parsing guide covers the separate missing-year problem. Keep those input contracts distinct when writing error messages and tests.