calendar.Calendar.itermonthdates(year, month) yields datetime.date objects for every day of a month, plus dates from the previous and following months needed to complete each calendar week. The default week starts on Monday.
This example prints every date in the calendar grid for July 2020:
import calendar
my_cal = calendar.Calendar()
for x in my_cal.itermonthdates(2020, 7):
print(x)
Output (first and last dates):
2020-06-29
2020-06-30
2020-07-01
2020-07-02
2020-07-03
2020-07-04
... (middle dates omitted) ...
2020-07-28
2020-07-29
2020-07-30
2020-07-31
2020-08-01
2020-08-02
2020-06-29
2020-06-30
2020-07-01
2020-07-02
2020-07-03
2020-07-04
2020-07-05
2020-07-06
2020-07-07
2020-07-08
2020-07-09
2020-07-10
2020-07-11
2020-07-12
2020-07-13
2020-07-14
2020-07-15
2020-07-16
2020-07-17
2020-07-18
2020-07-19
2020-07-20
2020-07-21
2020-07-22
2020-07-23
2020-07-24
2020-07-25
2020-07-26
2020-07-27
2020-07-28
2020-07-29
2020-07-30
2020-07-31
2020-08-01
2020-08-02The first date is 2020-06-29 and the last is 2020-08-02. Those four adjacent-month dates complete the Monday–Sunday week rows. The iterator contains 35 dates, not just July’s 31 days.
Run the July example, change the starting weekday, filter dates and complete short exercises with self-checking assertions.
Uses only the Python standard library. Upload the companion notebook to your Python-basics GitHub repository before publishing these links.
Use calendar.Calendar(firstweekday=0).itermonthdates(year, month). The Calendar instance determines the first weekday; the method accepts a year and month.
| Argument | Purpose | Example |
|---|---|---|
year | Calendar year to inspect; for this method, returned dates must fit in datetime.date | 2020 |
month | Month number from 1 (January) through 12 (December) | 7 |
firstweekday | Optional Calendar constructor setting: Monday 0 to Sunday 6 | 5 for Saturday |
The result is a Python iterator containing datetime.date objects rather than strings or integer day numbers. Each completed week always contains seven dates. See the first weekday setting for more options.
The method yields real datetime.date objects, allowing date comparisons and formatting without parsing printed strings.
import calendar
from datetime import date
first_date = next(calendar.Calendar().itermonthdates(2020, 7))
print(first_date)
print(type(first_date).__name__)
print(isinstance(first_date, date))
Output:
2020-06-29
date
True
Printing a date displays its ISO-formatted representation. The object itself has date methods and attributes.
The original Saturday-first example uses firstweekday=5. The month is unchanged, but the first and last dates in its complete-week grid change.
import calendar
my_cal = calendar.Calendar(firstweekday=5)
for x in my_cal.itermonthdates(2020, 7):
print(x)
Output (first and last dates):
2020-06-27
2020-06-28
2020-06-29
2020-06-30
2020-07-01
2020-07-02
... (middle dates omitted) ...
2020-07-26
2020-07-27
2020-07-28
2020-07-29
2020-07-30
2020-07-31
2020-06-27
2020-06-28
2020-06-29
2020-06-30
2020-07-01
2020-07-02
2020-07-03
2020-07-04
2020-07-05
2020-07-06
2020-07-07
2020-07-08
2020-07-09
2020-07-10
2020-07-11
2020-07-12
2020-07-13
2020-07-14
2020-07-15
2020-07-16
2020-07-17
2020-07-18
2020-07-19
2020-07-20
2020-07-21
2020-07-22
2020-07-23
2020-07-24
2020-07-25
2020-07-26
2020-07-27
2020-07-28
2020-07-29
2020-07-30
2020-07-31For this Saturday–Friday calendar, the iterator begins on 2020-06-27 and ends on 2020-07-31. Monday remains weekday 0 and Saturday remains 5; only the displayed week ordering changes.
Each result has .year, .month and .day attributes. This keeps the original example for extracting these values.
import calendar
my_cal = calendar.Calendar()
for x in my_cal.itermonthdates(2020, 7):
print("Year:", x.year, ", Month:", x.month, ", Day :", x.day)
Output (selected lines):
Year: 2020 , Month: 6 , Day : 29
Year: 2020 , Month: 6 , Day : 30
Year: 2020 , Month: 7 , Day : 1
Year: 2020 , Month: 7 , Day : 2
... (middle dates omitted) ...
Year: 2020 , Month: 7 , Day : 30
Year: 2020 , Month: 7 , Day : 31
Year: 2020 , Month: 8 , Day : 1
Year: 2020 , Month: 8 , Day : 2
Year: 2020 , Month: 6 , Day : 29
Year: 2020 , Month: 6 , Day : 30
Year: 2020 , Month: 7 , Day : 1
Year: 2020 , Month: 7 , Day : 2
Year: 2020 , Month: 7 , Day : 3
Year: 2020 , Month: 7 , Day : 4
Year: 2020 , Month: 7 , Day : 5
Year: 2020 , Month: 7 , Day : 6
Year: 2020 , Month: 7 , Day : 7
Year: 2020 , Month: 7 , Day : 8
Year: 2020 , Month: 7 , Day : 9
Year: 2020 , Month: 7 , Day : 10
Year: 2020 , Month: 7 , Day : 11
Year: 2020 , Month: 7 , Day : 12
Year: 2020 , Month: 7 , Day : 13
Year: 2020 , Month: 7 , Day : 14
Year: 2020 , Month: 7 , Day : 15
Year: 2020 , Month: 7 , Day : 16
Year: 2020 , Month: 7 , Day : 17
Year: 2020 , Month: 7 , Day : 18
Year: 2020 , Month: 7 , Day : 19
Year: 2020 , Month: 7 , Day : 20
Year: 2020 , Month: 7 , Day : 21
Year: 2020 , Month: 7 , Day : 22
Year: 2020 , Month: 7 , Day : 23
Year: 2020 , Month: 7 , Day : 24
Year: 2020 , Month: 7 , Day : 25
Year: 2020 , Month: 7 , Day : 26
Year: 2020 , Month: 7 , Day : 27
Year: 2020 , Month: 7 , Day : 28
Year: 2020 , Month: 7 , Day : 29
Year: 2020 , Month: 7 , Day : 30
Year: 2020 , Month: 7 , Day : 31
Year: 2020 , Month: 8 , Day : 1
Year: 2020 , Month: 8 , Day : 2Use date.year, date.month and date.day to build a custom label. You do not need to split the date string manually.
Convert the iterator to a list when you need its length or want to access individual dates by index.
import calendar
all_dates = list(calendar.Calendar().itermonthdates(2020, 7))
print("Total dates:", len(all_dates))
print("First:", all_dates[0])
print("Last:", all_dates[-1])
print("Whole weeks:", len(all_dates) // 7)
Output:
Total dates: 35
First: 2020-06-29
Last: 2020-08-02
Whole weeks: 5
Depending on the month and firstweekday, the complete calendar grid can span four, five, or six weeks. That gives 28, 35, or 42 dates.
A frequent requirement is to keep only the dates belonging to the selected month. Check both year and month, particularly around December and January.
import calendar
selected_year, selected_month = 2020, 7
all_dates = calendar.Calendar().itermonthdates(selected_year, selected_month)
month_dates = [d for d in all_dates
if d.year == selected_year and d.month == selected_month]
print("Dates in month:", len(month_dates))
print("First:", month_dates[0])
print("Last:", month_dates[-1])
Output:
Dates in month: 31
First: 2020-07-01
Last: 2020-07-31
July has 31 dates; the four extra values from June and August are excluded. For examples using simple day numbers and 0 outside the month, see itermonthdays().
Those extra dates are useful when displaying a full monthly calendar grid. You can style them differently in a calendar application.
import calendar
all_dates = calendar.Calendar().itermonthdates(2020, 7)
adjacent = [d for d in all_dates if (d.year, d.month) != (2020, 7)]
print("Adjacent-month dates:", len(adjacent))
for day in adjacent:
print(day)
Output:
Adjacent-month dates: 4
2020-06-29
2020-06-30
2020-08-01
2020-08-02
For July 2020, two padding dates come from June and two from August. These values are real dates, not placeholders.
Pass the readable constant calendar.SUNDAY rather than remembering the number 6.
import calendar
cal = calendar.Calendar(firstweekday=calendar.SUNDAY)
dates = list(cal.itermonthdates(2020, 7))
print("First weekday number:", cal.getfirstweekday())
print("First date:", dates[0])
print("Last date:", dates[-1])
print("Number of dates:", len(dates))
Output:
First weekday number: 6
First date: 2020-06-28
Last date: 2020-08-01
Number of dates: 35
The year and month stay the same; only the boundaries of the complete Sunday–Saturday weeks change.
You can change an existing Calendar instance using setfirstweekday(). The change affects future iterations, not an already-created list of dates.
import calendar
cal = calendar.Calendar()
before = list(cal.itermonthdates(2020, 7))
cal.setfirstweekday(calendar.FRIDAY)
after = list(cal.itermonthdates(2020, 7))
print("Before:", before[0], "to", before[-1])
print("After:", after[0], "to", after[-1])
Output:
Before: 2020-06-29 to 2020-08-02
After: 2020-06-26 to 2020-08-06
For related methods that yield weekday numbers, read iterweekdays().
Because itermonthdates() always yields complete weeks for ordinary supported dates, split the list into groups of seven to build calendar rows.
import calendar
dates = list(calendar.Calendar().itermonthdates(2020, 7))
for start in range(0, len(dates), 7):
week = dates[start:start + 7]
print(" ".join(f"{d.day:02d}" for d in week))
Output:
29 30 01 02 03 04 05
06 07 08 09 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 01 02
This prints five Monday–Sunday rows. The first row includes June 29 and 30; the last includes August 1 and 2, even though the output shows only day numbers.
If you prefer a ready-made list of weeks, use Calendar.monthdatescalendar(). It produces a list of week lists, whereas itermonthdates() yields dates one at a time.
import calendar
cal = calendar.Calendar()
weeks = cal.monthdatescalendar(2020, 7)
print("Number of weeks:", len(weeks))
print("Dates in first week:", len(weeks[0]))
print("First week:", weeks[0])
print("Same flat dates:", [d for week in weeks for d in week]
== list(cal.itermonthdates(2020, 7)))
Output:
Number of weeks: 5
Dates in first week: 7
First week: [datetime.date(2020, 6, 29), datetime.date(2020, 6, 30), datetime.date(2020, 7, 1), datetime.date(2020, 7, 2), datetime.date(2020, 7, 3), datetime.date(2020, 7, 4), datetime.date(2020, 7, 5)]
Same flat dates: True
This is a convenient starting point for building one HTML table row per week. If you want a printable text calendar instead, see prmonth().
The .weekday() method uses Monday = 0 through Sunday = 6. Use strftime() for readable weekday names.
import calendar
days = list(calendar.Calendar().itermonthdates(2020, 7))[:7]
for d in days:
print(d.isoformat(), d.weekday(), d.strftime("%A"))
Output:
2020-06-29 0 Monday
2020-06-30 1 Tuesday
2020-07-01 2 Wednesday
2020-07-02 3 Thursday
2020-07-03 4 Friday
2020-07-04 5 Saturday
2020-07-05 6 Sunday
This can help with booking interfaces or calendars that show dates with weekday labels. The weekday number does not change when you set a different calendar first weekday.
To obtain only Monday-to-Friday dates in July, combine the month filter with d.weekday() < 5. This example does not account for public holidays.
import calendar
cal = calendar.Calendar()
workdays = [d for d in cal.itermonthdates(2020, 7)
if (d.year, d.month) == (2020, 7) and d.weekday() < 5]
print("Weekdays in July 2020:", len(workdays))
print("First workday:", workdays[0])
print("Last workday:", workdays[-1])
Output:
Weekdays in July 2020: 23
First workday: 2020-07-01
Last workday: 2020-07-31
The condition filters to the requested month and excludes Saturdays and Sundays. Business-specific holidays require an additional holiday calendar.
The method automatically includes February 29 in a leap year. You do not need separate date-generation logic for that month.
import calendar
cal = calendar.Calendar()
all_dates = list(cal.itermonthdates(2024, 2))
february = [d for d in all_dates if d.month == 2 and d.year == 2024]
print("February dates:", len(february))
print("Contains Feb 29:", any(d.day == 29 for d in february))
print("Calendar begins:", all_dates[0])
print("Calendar ends:", all_dates[-1])
Output:
February dates: 29
Contains Feb 29: True
Calendar begins: 2024-01-29
Calendar ends: 2024-03-03
See the Python calendar module tutorial for related leap-year utilities and calendar formatting methods.
Because values are real datetime.date objects, they support adding timedelta and formatting with strftime().
import calendar
from datetime import timedelta
dates = calendar.Calendar().itermonthdates(2020, 7)
first_day = next(d for d in dates if (d.year, d.month, d.day) == (2020, 7, 1))
print("Original:", first_day)
print("One week later:", first_day + timedelta(days=7))
print("Formatted:", first_day.strftime("%d %B %Y"))
Output:
Original: 2020-07-01
One week later: 2020-07-08
Formatted: 01 July 2020
Use the resulting date objects directly for scheduling; do not perform arithmetic on formatted date strings.
An iterator advances as you read it. After you exhaust it, a second loop over the same iterator has nothing left to yield. Create a new iterator or convert it to a list if you need to reuse the dates.
import calendar
cal = calendar.Calendar()
dates = cal.itermonthdates(2020, 7)
print("First item:", next(dates))
print("Remaining:", len(list(dates)))
print("After exhaustion:", len(list(dates)))
print("New iterator:", len(list(cal.itermonthdates(2020, 7))))
Output:
First item: 2020-06-29
Remaining: 34
After exhaustion: 0
New iterator: 35
The same one-time-consumption rule applies to many other Python iterators; see Python iterators.
Related calendar methods return different kinds of values. Choose the one that matches the information you need.
import calendar
cal = calendar.Calendar()
print("dates:", list(cal.itermonthdates(2020, 7))[:3])
print("days:", list(cal.itermonthdays(2020, 7))[:3])
print("days2:", list(cal.itermonthdays2(2020, 7))[:3])
print("days3:", list(cal.itermonthdays3(2020, 7))[:3])
Output:
dates: [datetime.date(2020, 6, 29), datetime.date(2020, 6, 30), datetime.date(2020, 7, 1)]
days: [0, 0, 1]
days2: [(0, 0), (0, 1), (1, 2)]
days3: [(2020, 6, 29), (2020, 6, 30), (2020, 7, 1)]
| Method | Returned data | Ideal use |
|---|---|---|
itermonthdates() | datetime.date | Date arithmetic, formatting, scheduling |
itermonthdays() | Day numbers, 0 outside month | Simple month grids |
itermonthdays2() | (day, weekday) tuples | Weekday-aware numbered grids |
itermonthdays3() | (year, month, day) tuples | Date parts, including out-of-range years |
Also see iterweekdays(), which returns one week of weekday numbers and does not generate month dates.
itermonthdates() uses datetime.date, which supports years 1 through 9999. At the boundaries, full weeks might need dates outside that range, which cannot be represented as date objects. Use itermonthdays3() for year/month/day integer tuples when exploring those extreme ranges.
import calendar
cal = calendar.Calendar()
values = list(cal.itermonthdays3(9999, 12))
print("First tuple:", values[0])
print("Last tuple:", values[-1])
print("Number of cells:", len(values))
Output:
First tuple: (9999, 11, 29)
Last tuple: (10000, 1, 2)
Number of cells: 35
The integer tuples can represent a year beyond 9999 when padding a calendar; converting them to datetime.date would not be valid. Normal modern-year calendars do not have this boundary problem.
month must be between 1 and 12. When the iterator is evaluated, an invalid month raises calendar.IllegalMonthError (a subclass of ValueError).
import calendar
try:
dates = list(calendar.Calendar().itermonthdates(2020, 13))
except calendar.IllegalMonthError:
print("Please enter a month from 1 to 12")
Output:
Please enter a month from 1 to 12
Validate data from forms or external inputs before using it in a calendar application. Avoid silently converting an invalid month to another month.
This small scheduling example creates a task only for weekdays within July 2020, not the extra padding dates or weekends.
import calendar
cal = calendar.Calendar()
assigned = 0
for d in cal.itermonthdates(2020, 7):
if (d.year, d.month) == (2020, 7) and d.weekday() < 5:
assigned += 1
if assigned <= 3:
print(d.isoformat(), "Review project tasks")
print("Total assigned days:", assigned)
Output:
2020-07-01 Review project tasks
2020-07-02 Review project tasks
2020-07-03 Review project tasks
Total assigned days: 23
For a real scheduling system, add a holiday list and store task assignments using your application’s data layer.
Use itermonthdates() when you want to iterate complete weeks and need fully functional date objects. Use monthdatescalendar() when you specifically need pre-grouped weeks, itermonthdays() when day numbers are enough, or prmonth() when you just want to print a calendar. These tools solve related but different problems.
| Problem | Why it happens | Solution |
|---|---|---|
| Extra dates appear before or after the month | The method completes seven-day weeks by design | Filter by both year and month if you only need target-month dates |
| Week starts on the wrong day | The default is Monday | Pass firstweekday=calendar.SUNDAY or another weekday when creating Calendar |
len() does not work on the iterator | The result is an iterator rather than a list | Use list(cal.itermonthdates(...)) before calling len() |
| Second iteration yields no dates | The same iterator was exhausted | Create a fresh iterator or keep a list of results |
| Invalid month raises an exception | Month number is not in 1–12 | Validate input and handle calendar.IllegalMonthError |
| Out-of-range year errors | datetime.date has a limited year range | Use itermonthdays3() when numeric tuples are sufficient |
itermonthdates() and itermonthdays3().Start the interactive Colab practice notebook to run the examples and check your answers. If you are new to Colab, read the Google Colab tutorial.
An iterator of datetime.date objects covering the requested month and the preceding/following dates needed to complete weeks.
Complete weekly rows let you build a monthly calendar grid without gaps. Filter by year and month if you only need dates inside the month.
Monday (0), unless you configure a different firstweekday on the Calendar object.
Normally 28, 35 or 42 dates: four, five or six complete seven-day weeks, depending on month and starting weekday.
Actual datetime.date objects. They print in ISO-like format but can be compared, formatted and used for date arithmetic.
Use a comprehension keeping values whose (date.year, date.month) matches the requested year and month.
Yes. calendar and datetime belong to the standard library; no extra installation is needed.
Padding may fall outside the datetime.date range. Use itermonthdays3() for numeric tuples at those boundaries.
Both provide date objects for complete weeks. itermonthdates() is a flat iterator; monthdatescalendar() returns a list of week lists.
Ready to experiment? Return to the Colab and GitHub practice notebook.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.