calendar.itermonthdates() Crashes on December 9999 -- Sibling Methods Don't (tested)

calendar.Calendar has several methods that all compute the exact same thing -- a month's full day grid, including the leading/trailing days from the adjacent months needed to fill whole weeks. They differ only in what type they hand back: plain integers, (day, weekday) tuples, or actual datetime.date objects. We measured what happens when that month happens to be December of year 9999, one month before datetime's own upper limit.

1. Same month, same class, different method -- one crashes, the others don't

import calendar

c = calendar.Calendar()

for name, fn in [
    ("itermonthdates",       lambda: list(c.itermonthdates(9999, 12))),
    ("itermonthdays2",       lambda: list(c.itermonthdays2(9999, 12))),
    ("itermonthdays3",       lambda: list(c.itermonthdays3(9999, 12))),
    ("itermonthdays4",       lambda: list(c.itermonthdays4(9999, 12))),
    ("monthdatescalendar",   lambda: c.monthdatescalendar(9999, 12)),
    ("monthdays2calendar",   lambda: c.monthdays2calendar(9999, 12)),
]:
    try:
        r = fn()
        print(name, "OK, len", len(r))
    except Exception as e:
        print(name, "RAISED", type(e).__name__, e)
itermonthdates RAISED ValueError year 10000 is out of range
itermonthdays2 OK, len 35
itermonthdays3 OK, len 35
itermonthdays4 OK, len 35
monthdatescalendar RAISED ValueError year 10000 is out of range
monthdays2calendar OK, len 5

Measured: December 9999's trailing days spill into January of year 10000. The methods that represent each day as a datetime.date object (itermonthdates, monthdatescalendar) have to actually construct a date in year 10000 to do that -- and datetime.date's hard limit is year 9999, so construction raises. The methods that represent the same days as plain integers or (day, weekday) tuples (itermonthdays2/3/4, monthdays2calendar) never construct a date object at all, so the identical trailing days pass through with no error.

2. The exception you actually get doesn't match the one the docs describe

import calendar
help(calendar.Calendar.itermonthdates)
# relevant excerpt from the official docstring/docs:
# "it's possible to get an OverflowError for dates that are too far
#  into the future or past (near datetime.MAXYEAR or MINYEAR)."
import calendar
c = calendar.Calendar()
try:
    list(c.itermonthdates(9999, 12))
except Exception as e:
    print(type(e).__name__, e)
ValueError year 10000 is out of range

Measured: the documented caveat names OverflowError; what's actually raised measured here is ValueError, coming straight from the datetime.date(year, month, day) constructor's own range check. Catching OverflowError specifically around a call to itermonthdates() -- which is exactly what the documentation's own wording suggests -- does not catch this.

3. It isn't only the far future -- the same split exists building a calendar display

import calendar

c = calendar.Calendar()
try:
    weeks = c.monthdatescalendar(9999, 12)   # a typical "render this month" call
except ValueError as e:
    print("monthdatescalendar failed:", e)

# the integer-based equivalent, same month, same shape, no crash:
weeks2 = c.monthdays2calendar(9999, 12)
print("monthdays2calendar still works, weeks:", len(weeks2))
monthdatescalendar failed: year 10000 is out of range
monthdays2calendar still works, weeks: 5

Measured: if a calendar UI or report builder picks the date-object variant because it's more convenient to work with downstream, it inherits a crash at the exact year boundary that the integer-based sibling method never hits -- on data that's otherwise perfectly ordinary month arithmetic.

Frequently asked questions

Does calendar.itermonthdates() crash near datetime's year limits?

Yes -- we measured calendar.Calendar().itermonthdates(9999, 12) raising ValueError, because December 9999's trailing days spill into January of year 10000, past datetime.date's maximum year of 9999.

Do the other calendar.Calendar methods for the same month also crash?

No -- we measured itermonthdays2(), itermonthdays3(), itermonthdays4() and monthdays2calendar() all returning the identical month grid successfully for year 9999, December, because they represent days as plain integers or tuples rather than datetime.date objects.

What exception type should I catch around calendar.itermonthdates() for this case?

We measured ValueError being raised, not the OverflowError that the method's own documented caveat names -- catching only OverflowError around this call does not catch the actual exception.

Is this only a problem for extremely far-future years like 9999?

In practice yes -- we measured the failure specifically at December of datetime.MAXYEAR (9999), one month before the hard upper limit; every other month and the date-based methods for earlier years worked without issue in our tests.

Written with AI assistance. Measured on 2026-10-08 with Python 3.13.5's built-in calendar module: called calendar.Calendar()'s itermonthdates(), itermonthdays2(), itermonthdays3(), itermonthdays4() and monthdatescalendar() all on the same month (year 9999, December) and compared which ones raised and which returned normally. PlainHeaders is our extension; Python's calendar module is built in.