calendar.TextCalendar.prmonth() prints a month as an aligned, plain-text calendar. Pass a year and month, and optionally adjust the date-column width (w) and lines per week (l).
Here is a complete example printing July 2020 with wider date columns:
import calendar
x = calendar.TextCalendar()
x.prmonth(2020, 7, w=5, l=1)
Output:
July 2020
Mon Tue Wed Thu Fri Sat Sun
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
The output starts on Monday because TextCalendar() defaults to Monday (0). Spaces align the dates into columns, so use a monospaced font to display the result correctly.
Run the example, switch the first weekday, change w and l, and complete exercises with automatic checks.
The notebook uses only Python's standard library. Publish the companion notebook to your Python-basics repository before using these links.
The method belongs to calendar.TextCalendar. Its signature is prmonth(theyear, themonth, w=0, l=0).
| Parameter | Meaning | Example |
|---|---|---|
theyear | Year to display | 2020 |
themonth | Month number from 1 (January) to 12 (December) | 7 |
w | Minimum width of the date columns in text characters; omitted or 0 uses the effective minimum of 2 | w=5 |
l | Lines allocated to each week; omitted or 0 uses the effective minimum of 1 | l=2 |
Note: w is character spacing, not CSS pixels; l adds vertical spacing between calendar weeks. These are formatting settings, not the number of weekdays or weeks printed.
Weekday numbering is fixed: Monday is 0, Tuesday 1, through Sunday 6. A Friday-first calendar begins each row with Friday, but it does not renumber the days. This retains the original example.
import calendar
x = calendar.TextCalendar()
x.setfirstweekday(4) # Friday
x.prmonth(theyear=2020, themonth=7, w=3, l=0)
Output:
July 2020
Fri Sat Sun Mon Tue Wed Thu
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
The same July dates appear under a Friday–Thursday header. To understand the setting, see setting the first weekday in Python and iterating weekday numbers.
For a normal Monday-first calendar you can call calendar.prmonth() directly, without creating a TextCalendar object. This uses the calendar module's configured first weekday.
import calendar
calendar.prmonth(2020, 7)
Output:
July 2020
Mo Tu We Th Fr Sa Su
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
For code needing different start days in different places, use separate TextCalendar instances. That avoids changing the module-level first-weekday setting for other code.
A larger w allocates more characters to each date column. Below, w=2 keeps the calendar compact; compare it with the first example's w=5.
import calendar
x = calendar.TextCalendar()
x.prmonth(2020, 7, w=2, l=1)
Output:
July 2020
Mo Tu We Th Fr Sa Su
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
When w is 0 or 1, Python still needs at least two characters for date values such as 30 and 31.
Use l=2 to leave a blank line after each week. This makes a printed schedule easier to annotate, but it doesn't change which dates belong to each week.
import calendar
x = calendar.TextCalendar()
x.prmonth(2020, 7, w=2, l=2)
Output:
July 2020
Mo Tu We Th Fr Sa Su
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
With l=0 or l=1, the calendar uses one line for each week.
You can pass calendar.SUNDAY rather than remembering that Sunday is 6. The order changes without changing date values.
import calendar
x = calendar.TextCalendar(firstweekday=calendar.SUNDAY)
x.prmonth(2020, 7, w=2, l=1)
Output:
July 2020
Su Mo Tu We Th Fr Sa
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Use setfirstweekday() on the object to change its display order. Below, the two headers show the effect without printing the whole month twice.
import calendar
x = calendar.TextCalendar()
print(x.formatmonth(2020, 7).splitlines()[1])
x.setfirstweekday(calendar.FRIDAY)
print(x.formatmonth(2020, 7).splitlines()[1])
Output:
Mo Tu We Th Fr Sa Su
Fr Sa Su Mo Tu We Th
setfirstweekday() changes this TextCalendar instance; it does not change the names or fixed weekday numbers.
This distinction is useful when you want to keep the calendar for an email, text file, or log. prmonth() writes to standard output; formatmonth() returns the same layout as a string.
import calendar
x = calendar.TextCalendar()
month_text = x.formatmonth(2020, 7)
print(type(month_text).__name__)
print(month_text.splitlines()[0].strip())
print(month_text.splitlines()[1])
Output:
str
July 2020
Mo Tu We Th Fr Sa Su
formatmonth() does not automatically print anything. The print() calls above display selected lines from the returned string.
prmonth() is designed for direct output, not for creating a reusable string. Assigning its result to a variable still prints the calendar, but the assigned value is None.
import calendar
x = calendar.TextCalendar()
result = x.prmonth(2020, 7)
print("Returned None:", result is None)
Output:
July 2020
Mo Tu We Th Fr Sa Su
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Returned None: True
If you need a string, call formatmonth() instead of trying to concatenate or save result.
If you must capture output from existing code that calls prmonth(), use contextlib.redirect_stdout() with io.StringIO(). For new code, formatmonth() is simpler.
import calendar
from contextlib import redirect_stdout
from io import StringIO
buffer = StringIO()
with redirect_stdout(buffer):
calendar.prmonth(2020, 7)
text = buffer.getvalue()
print(text.splitlines()[0].strip())
print("Characters captured:", len(text) > 50)
Output:
July 2020
Characters captured: True
The redirected text contains newlines and alignment spaces. This is suitable for capturing plain-text output; it is not HTML markup.
Because formatmonth() returns a string, it is the direct option for saving a calendar. This example creates july-2020-calendar.txt in the folder where Python is running.
import calendar
from pathlib import Path
x = calendar.TextCalendar()
path = Path("july-2020-calendar.txt")
path.write_text(x.formatmonth(2020, 7), encoding="utf-8")
print("Saved:", path.name)
print("Month:", path.read_text(encoding="utf-8").splitlines()[0].strip())
Output:
Saved: july-2020-calendar.txt
Month: July 2020
On Colab the file is created in the runtime's working directory. It is not automatically uploaded to GitHub or saved permanently to your Google Drive.
A loop can print a consecutive set of calendars. This compact example prints the title lines for June through August 2020; remove .splitlines()[0].strip() to display each full calendar using formatmonth().
import calendar
x = calendar.TextCalendar()
for month in (6, 7, 8):
title = x.formatmonth(2020, month).splitlines()[0].strip()
print(title)
Output:
June 2020
July 2020
August 2020
You can also replace the loop body with x.prmonth(2020, month) to print three complete month grids.
Month values must be integers from 1 to 12. The example checks user-supplied values before calling prmonth(); web applications should also validate the year and handle malformed input.
import calendar
year = 2024
month = 13
if isinstance(month, int) and 1 <= month <= 12:
calendar.prmonth(year, month)
else:
print("Please enter a month from 1 to 12.")
Output:
Please enter a month from 1 to 12.
Calling calendar.prmonth(2024, 13) directly raises an exception for the invalid month. Validate external input and avoid passing arbitrary strings directly to calendar functions.
The calendar module handles leap years automatically. monthrange() is useful when you need a month's starting weekday and number of days, rather than a printed grid.
import calendar
print("February 2024:", calendar.monthrange(2024, 2))
print("February 2023:", calendar.monthrange(2023, 2))
print("July 1, 2020 weekday:", calendar.weekday(2020, 7, 1))
Output:
February 2024: (calendar.THURSDAY, 29)
February 2023: (calendar.WEDNESDAY, 28)
July 1, 2020 weekday: 2
The weekday returned for July 1, 2020 is 2 (Wednesday). This numerical convention stays the same even if your printed calendar begins on Friday or Sunday.
| Function | Result | Good for |
|---|---|---|
calendar.prmonth(year, month) | Prints a text calendar | Simple scripts and console output |
calendar.TextCalendar().prmonth(...) | Prints a text calendar with object-specific week settings | Custom week starts |
calendar.TextCalendar().formatmonth(...) | Returns a multiline string | Saving and reusing text |
calendar.month(year, month) | Returns a multiline string using module settings | Quick string formatting |
calendar.HTMLCalendar().formatmonth(...) | Returns HTML table markup | HTML calendar pages |
calendar.monthrange(year, month) | Returns starting weekday and day count | Date calculations |
For details of raw date iteration, explore itermonthdays(), itermonthdays2(), and itermonthdays3().
Text calendars rely on spaces. Display output in a <pre> element or another element styled with a monospaced font and white-space: pre. Plain HTML collapses repeated spaces and newlines.
prmonth() prints its output and returns None. Use formatmonth() for text you want to store or manipulate.
Pass firstweekday=calendar.SUNDAY or call setfirstweekday() on your TextCalendar object. See firstweekday options.
Use an integer month between 1 and 12. A form value such as "7" is a string and should be validated and converted before calling the calendar method.
Values below the effective minimum are treated as the minimum: two characters per date column and one line per week. Try w=5 or l=2 to see the difference.
Try these challenges using the Colab notebook above. Its cells include solutions and self-checking assertions.
w=2 and w=5 change the output.l=2; count the blank lines added between weeks.formatmonth() to save a month calendar as a text file.13 before rendering a calendar.Small challenge: Can you display the month name using calendar.month_name[month] without printing the full grid?
It prints a formatted, plain-text calendar for a given year and month.
Both calendar.prmonth() and calendar.TextCalendar().prmonth() are available. The latter is an instance method you can configure independently.
No. Its return value is None. Use formatmonth() or calendar.month() for a string.
Use calendar.TextCalendar(firstweekday=calendar.SUNDAY) or set the weekday to 6 on the object.
No. calendar is part of the Python standard library.
Not directly: prmonth() produces plain text. For an HTML table, use calendar.HTMLCalendar().formatmonth() and handle any custom content with appropriate HTML escaping.
Yes. The printed February calendar uses the actual number of days for the selected year.
Want to work through the examples? Open the Colab or 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.