Calendar Maker
This program generates printable text files of monthly calendars for the month and year you enter. Dates and calendars are a tricky topic in programming because there are so many different rules for determining the number of days in a month, which years are leap years, and which day of the week a particular date falls on. Fortunately, Python’s datetime module handles these details for you. This program focuses on generating the multiline string for the monthly calendar page.
calendar_maker.py
1"""Calendar Maker, by Al Sweigart al@inventwithpython.com
2Create monthly calendars, saved to a text file and fit for printing.
3This code is available at https://nostarch.com/big-book-small-python-programming
4Tags: short"""
5
6import datetime
7
8# Set up the constants:
9DAYS = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday',
10 'Friday', 'Saturday')
11MONTHS = ('January', 'February', 'March', 'April', 'May', 'June', 'July',
12 'August', 'September', 'October', 'November', 'December')
13
14print('Calendar Maker, by Al Sweigart al@inventwithpython.com')
15
16while True: # Loop to get a year from the user.
17 print('Enter the year for the calendar:')
18 response = input('> ')
19
20 if response.isdecimal() and int(response) > 0:
21 year = int(response)
22 break
23
24 print('Please enter a numeric year, like 2023.')
25 continue
26
27while True: # Loop to get a month from the user.
28 print('Enter the month for the calendar, 1-12:')
29 response = input('> ')
30
31 if not response.isdecimal():
32 print('Please enter a numeric month, like 3 for March.')
33 continue
34
35 month = int(response)
36 if 1 <= month <= 12:
37 break
38
39 print('Please enter a number from 1 to 12.')
40
41
42def getCalendarFor(year, month):
43 calText = '' # calText will contain the string of our calendar.
44
45 # Put the month and year at the top of the calendar:
46 calText += (' ' * 34) + MONTHS[month - 1] + ' ' + str(year) + '\n'
47
48 # Add the days of the week labels to the calendar:
49 # (!) Try changing this to abbreviations: SUN, MON, TUE, etc.
50 calText += '...Sunday.....Monday....Tuesday...Wednesday...Thursday....Friday....Saturday..\n'
51
52 # The horizontal line string that separate weeks:
53 weekSeparator = ('+----------' * 7) + '+\n'
54
55 # The blank rows have ten spaces in between the | day separators:
56 blankRow = ('| ' * 7) + '|\n'
57
58 # Get the first date in the month. (The datetime module handles all
59 # the complicated calendar stuff for us here.)
60 currentDate = datetime.date(year, month, 1)
61
62 # Roll back currentDate until it is Sunday. (weekday() returns 6
63 # for Sunday, not 0.)
64 while currentDate.weekday() != 6:
65 currentDate -= datetime.timedelta(days=1)
66
67 while True: # Loop over each week in the month.
68 calText += weekSeparator
69
70 # dayNumberRow is the row with the day number labels:
71 dayNumberRow = ''
72 for i in range(7):
73 dayNumberLabel = str(currentDate.day).rjust(2)
74 dayNumberRow += '|' + dayNumberLabel + (' ' * 8)
75 currentDate += datetime.timedelta(days=1) # Go to next day.
76 dayNumberRow += '|\n' # Add the vertical line after Saturday.
77
78 # Add the day number row and 3 blank rows to the calendar text.
79 calText += dayNumberRow
80 for i in range(3): # (!) Try changing the 4 to a 5 or 10.
81 calText += blankRow
82
83 # Check if we're done with the month:
84 if currentDate.month != month:
85 break
86
87 # Add the horizontal line at the very bottom of the calendar.
88 calText += weekSeparator
89 return calText
90
91
92calText = getCalendarFor(year, month)
93print(calText) # Display the calendar.
94
95# Save the calendar to a text file:
96calendarFilename = 'calendar_{}_{}.txt'.format(year, month)
97with open(calendarFilename, 'w') as fileObj:
98 fileObj.write(calText)
99
100print('Saved to ' + calendarFilename)