Python has a built-in library to print a calendar directly, but you can also create your own implementation. This article covers both methods.
Method 1: Using the Built-in calendar Module
The calendar module provides functions to display calendars. Here's a simple example:
import calendar
year = int(input("Enter year: "))
month = int(input("Enter month: "))
# Print calendar for a specific month
print(calendar.month(year, month))
# Print calendar for the entire year
calendar.prcal(year)
Sample output:
Enter year: 2017
Enter month: 3
March 2017
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
2017
January February March
...
You can adjust the first day of the week using setfirstweekday(). For example, to start weeks on Sunday:
calendar.setfirstweekday(6) # Sunday is 6
calendar.prcal(2016)
Method 2: Custom Implementation
You can implement your own calendar printing function to understand the logic. The custom implementation includes the following helper functions:
is_leap(year): Determine if a year is a leap year.month_days(year, month): Get the number of days in a given month.total_days_since_1800(year, month): Calculate days elapsed since January 1, 1800.first_day_of_month(year, month): Determine the day of the week for the first day of the month using Zeller's congruence.print_month_title(year, month): Print the month's header.print_month_body(year, month): Print the days of the month.
Here's the complete implementation:
def is_leap(year):
"""Return True if year is a leap year."""
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
def month_days(year, month):
if month in (1, 3, 5, 7, 8, 10, 12):
return 31
elif month in (4, 6, 9, 11):
return 30
elif is_leap(year):
return 29
else:
return 28
def total_days_since_1800(year, month):
"""Calculate days from January 1, 1800 to the first of the given month."""
days = 0
for y in range(1800, year):
days += 366 if is_leap(y) else 365
for m in range(1, month):
days += month_days(year, m)
return days
def first_day_of_month(year, month):
"""Return the day of week of the first day of the month (0=Sunday, 1=Monday, ..., 6=Saturday)."""
# Zeller's congruence for Gregorian calendar
if month < 3:
month += 12
year -= 1
q = 1 # day of month
m = month
J = year // 100
K = year % 100
h = (q + (13 * (m + 1)) // 5 + K + K // 4 + J // 4 + 5 * J) % 7
# Convert h (0=Saturday, 1=Sunday, ..., 6=Friday) to our desired representation (0=Sunday, ..., 6=Saturday)
return (h + 6) % 7
MONTH_NAMES = [
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
]
def month_name(month):
return MONTH_NAMES[month - 1]
def print_month_title(year, month):
print(f"{month_name(month)} {year}".center(45))
print("-" * 45)
print(" Sun Mon Tue Wed Thu Fri Sat")
def print_month_body(year, month):
first_day = first_day_of_month(year, month)
days = month_days(year, month)
# Print leading spaces
print(" " * (5 * first_day + 2), end="") # 2 initial spaces, 5 per day
for day in range(1, days + 1):
print(f"{day:4d} ", end="")
first_day += 1
if first_day == 7:
print()
first_day = 0
print(" ", end="") # initial spaces for new line
print() # final newline
def print_calendar(year, month=None):
if month is None:
for m in range(1, 13):
print_month_title(year, m)
print_month_body(year, m)
print()
else:
print_month_title(year, month)
print_month_body(year, month)
# Example usage
if __name__ == "__main__":
year = int(input("Enter year: "))
month = int(input("Enter month: "))
print_calendar(year, month)
In this custom implementation, we used Zeller's congruence to determine the first day of the month. The printing format uses a width of 5 characters per day, with Sunday as the first column. The function print_calendar can print a single month or a entire year.