calendar

The calendar module has a ton of cool tools for dealing with (can you guess?) calendars. By default the module uses Monday as the first day of the week and Sunday as the last. Note that it accesses the datetime module code. We only cover a few of the highlights in this session.

First let’s get everybody’s favorite – the fun, easy calendar function – out of the way. Presenting TextCalendar, whereby we create a calendar object and then use the pryear function to generate the output.

import calendar
c=calendar.TextCalendar(calendar.SUNDAY)
c.pryear(2017,w=2,l=1,c=6,m=3)


Note this calendar must use a monospaced font like Consolas. “calendar.SUNDAY” tells the code that you want the weeks to start with Sunday instead of Monday.

Almost as much fun and maybe more useful is the formatmonth method:

c=calendar.TextCalendar(calendar.MONDAY)
c.setfirstweekday(calendar.SUNDAY)
print(c.formatmonth(2017,1,w=0,l=0))
 

The module has functions for a number of iterators, see https://docs.python.org/3/library/calendar.html:
iterweekdays()
itermonthdates(year,month)
itermonthdays2(year,month)
itermonthdays(year, month)

Example: itermonthdays2 gives tuples of day number and week day number with leading or following days numbered 0 (zero) indicating days of other months necessary to fill in the full weeks.

import calendar
mycal = calendar.Calendar()
myiter=mycal.itermonthdays2(2017,2)
for i in myiter:
    print (i, end=", ")

….yields….
(0, 0), (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 0), (7, 1), (8, 2), (9, 3), (10, 4), (11, 5), (12, 6), (13, 0), (14, 1), (15, 2), (16, 3), (17, 4), (18, 5), (19, 6), (20, 0), (21, 1), (22, 2), (23, 3), (24, 4), (25, 5), (26, 6), (27, 0), (28, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6),

Let’s say for example you need to know what day of the week the 15th of every month falls on for the year 2017:

import calendar
mos=("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec")
days=("Mon","Tue","Wed","Thr","Fri","Sat","Sun")
mycal = calendar.Calendar()
for mo in range(0,12):
    moTup=()
    print(mos[mo],end=": ")
    moiter=mycal.itermonthdays2(2017,mo+1)
    for i in moiter:
        if i[0]==15:
            print(days[i[1]])

….yields….
Jan: Sun
Feb: Wed
Mar: Wed
Apr: Sat
May: Mon
Jun: Thr
Jul: Sat
Aug: Tue
Sep: Fri
Oct: Sun
Nov: Wed
Dec: Fri

Several functions return lists of weeks in on form or another:
monthdatescalendar(year, month)
monthdays2calendar(year, month)
monthdayscalendar(year, month)

For example:

mycal=calendar.Calendar()
print(mycal.monthdatescalendar(2017,7))

…..yields….. a list of weeks or the year and month, each week having 7 datetime objects
[[datetime.date(2017, 6, 26), datetime.date(2017, 6, 27), datetime.date(2017, 6, 28), datetime.date(2017, 6, 29), datetime.date(2017, 6, 30), datetime.date(2017, 7, 1), datetime.date(2017, 7, 2)], [datetime.date(2017, 7, 3), datetime.date(2017, 7, 4), datetime.date(2017, 7, 5), datetime.date(2017, 7, 6), datetime.date(2017, 7, 7), datetime.date(2017, 7, 8), datetime.date(2017, 7, 9)], [datetime.date(2017, 7, 10), datetime.date(2017, 7, 11), datetime.date(2017, 7, 12), datetime.date(2017, 7, 13), datetime.date(2017, 7, 14), datetime.date(2017, 7, 15), datetime.date(2017, 7, 16)], [datetime.date(2017, 7, 17), datetime.date(2017, 7, 18), datetime.date(2017, 7, 19), datetime.date(2017, 7, 20), datetime.date(2017, 7, 21), datetime.date(2017, 7, 22), datetime.date(2017, 7, 23)], [datetime.date(2017, 7, 24), datetime.date(2017, 7, 25), datetime.date(2017, 7, 26), datetime.date(2017, 7, 27), datetime.date(2017, 7, 28), datetime.date(2017, 7, 29), datetime.date(2017, 7, 30)], [datetime.date(2017, 7, 31), datetime.date(2017, 8, 1), datetime.date(2017, 8, 2), datetime.date(2017, 8, 3), datetime.date(2017, 8, 4), datetime.date(2017, 8, 5), datetime.date(2017, 8, 6)]

There are three methods for returning unformatted year data:
yeardatescalendar(year, width=3)
yeardays2calendar(year, width=3)
yeardayscalendar(year, width=3)

For example:

mycal=calendar.Calendar(calendar.SUNDAY)
print(mycal.yeardayscalendar(2017)) 

……yields lists of dates for the year nested by [year [quarter [month [week day list]]]]
[[[[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, 0, 0, 0, 0]], [[0, 0, 0, 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, 0, 0, 0, 0]], [[0, 0, 0, 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, 0]]], [[[0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0]], [[0, 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, 0, 0, 0]], [[0, 0, 0, 0, 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, 0]]], [[[0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0]], [[0, 0, 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, 0, 0]], [[0, 0, 0, 0, 0, 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]]], [[[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, 0, 0, 0, 0]], [[0, 0, 0, 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, 0, 0]], [[0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0]]]]
…so you easily access any grouping from quarter to day by nesting slices of this data, i.e.,:

import calendar
mycal=calendar.Calendar(calendar.SUNDAY)
dateslist=mycal.yeardayscalendar(2017)
Quarter = 0 #1ST QUARTER
Month=1     #2ND MONTH
Week = 1     #2nd WEEK
Day = 4       #5TH DAY if we start with Sundays=0
print(dateslist[Quarter][Month][Week][Day]) 

… yields…
9 i.e., the date of the 5th day, 2nd week, 2nd month of the 1st quarter of the year.

Now, some fun functions for text calendars, you need to look at the code alongside the result:

import calendar
c=calendar.TextCalendar()
print('Note: Monday = 0, Sunday = 6')
print("by default 1st week day is: ",calendar.firstweekday())
calendar.setfirstweekday(6)  # set first week day to Sunday
print ("first weekday changed to: ",calendar.firstweekday())
print("is 2016 a leap year:", calendar.isleap(2016))
print("is 2017 a leap year:", calendar.isleap(2017))
print("how many leapday from 2000 to 2050? ",calendar.leapdays(2000,2050))
print( 'day of the week for  2017, Feb (2), 4 (day): ',calendar.weekday(2017,2,4))
print("Note that the fact we earlier set 1st weekday to Sunday does not change it for this function.")
print(calendar.weekheader(10))
print("...but it does for this one. This is NOT in the official docs")
print('monthrange tells us September 2017 starts on Friday and has 30 days.')
print(calendar.monthrange(2017,9))
print('monthcalendar gives us a matrix of June, 2017:')
print(calendar.monthcalendar(2017,6))
print('prmonth gives us a month calendar, ex for January 2017')
print(calendar.prmonth(2017,1,10,0))
print('note this must be printed in a monospace like Consolas to work.')
print("if you need the month in a multiline string use month - March 2017:")
print(calendar.month(2017,3))
print("here is output from prcal")
print(calendar.prcal(2017))
print("and here is calendar.calendar for 2016")
print(calendar.calendar(2016))
print('and the module exports day and month names and abbreviations')
print('but we could not make that function work')

….yields….
Note: Monday = 0, Sunday = 6
by default 1st week day is: 0
first weekday changed to: 6
is 2016 a leap year: True
is 2017 a leap year: False
how many leapday from 2000 to 2050? 13
day of the week for 2017, Feb (2), 4 (day): 5
Note that the fact we earlier set 1st weekday to Sunday does not change it for this function.
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
…but it does for this one. This is NOT in the official docs
monthrange tells us September 2017 starts on Friday and has 30 days.
(4, 30)
monthcalendar gives us a matrix of June, 2017:
[[0, 0, 0, 0, 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, 0]]
prmonth gives us a month calendar, ex for January 2017
January 2017
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
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
None
note this must be printed in a monospace like Consolas to work.
if you need the month in a multiline string use month – March 2017:
March 2017
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

here is output from prcal


and here is calendar.calendar for 2016
2016

and the module exports day and month names and abbreviations
but we could not make that function work