Python's calendar module is part of the standard library. It allows the output of a calendar by month or by year and also provides other, calendar-related functionality.
The calendar module itself depends on the datetime module. But we will also need datetime for our own purposes, as we will see. So we should import both of these. Also, in order to do some string splitting, we will need the re module. Let's import them all in one go.
import re, datetime, calendar
By default, the calendars begin the week with Monday (day 0), per the European convention, and ends with Sunday (day 6). If you prefer Sunday as the first day of the week, use the setfirstweekday() method to change the default to day 6 as follows:
To toggle between the two, you could pass the first day of the week as an argument using the sys module. You would then check the value with an if statement and set the setfirstweekday() method accordingly.
import sys firstday = sys.argv if firstday == "6": calendar.setfirstweekday(6)
In our calendar, it would be nice to have a header for the calendar that reads something like "A Python-Generated Calendar For..." and have the current month and year. In order to do this, we need to get the month and year from the system. This functionality is something that calendar provides, Python can retrieve the month and year. But we still have a problem. As all system dates are numeric and do not contain unabbreviated or non-numeric forms of the months, we need a list of those months. Enter the list year.
Now when we get the number of a month, we can access that number (minus one) in the list and get the full month name.
year = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
Starting the main() function, let's ask datetime for the time.
def main(): today = datetime.datetime.date(datetime.datetime.now())
Curiously, the datetime module has a datetime class. It is from this class that we call two objects: now() and date(). The method datetime.datetime.now() returns an object containing the following information: year, month, date, hour, minute, second, and microseconds. Of course, we have no need for the time information. To cull out the date information alone, we pass the results of now() to datetime.datetime.date() as an argument. The result is that today now contains the year, month, and date separated by em-dashes.
To break this bit of data into more managable pieces, we must split it. We can then assign the parts to the variables current_yr, current_month, and current_day respectively.
current = re.split('-', str(today)) current_no = int(current) current_month = year[current_no-1] current_day = int(re.sub('\A0', '', current)) current_yr = int(current)
To understand the first line of this code, work from the right to the left and from the inside outward. First, we stringify the object today in order to operate on it as a string. Then, we split it using the em-dash as a delimiter, or token. Finally, we assign those three values as a list to 'current'.
In order to deal with these values more distinctly and to call the long name of the current month out of year, we assign the number of the month to current_no. We can then do a bit of subtraction in the subscript of year and assign the month name to current_month.
In the next line, a bit of substitution is needed. The date which is returned from datetime is a two-digit value even for the first nine days of the month. A zero functions as a place holder, but we would rather our calendar have just the single digit. So we substitute no value for every zero that begins a string (hence '\A'). Finally, we assign the year to current_yr, converting it to an integer along the way.
Methods that we will call later will require input in integer format. Therefore, it is important to ensure that all of the date data is saved in integer, not string, form.
Before we print the calendar, we need to print the HTML preamble and CSS layout for our calendar. Go to this page for the code to print the CSS and HTML preamble for the calendar. and copy the code into your program file. The CSS in the HTML of this file follows the template offered by Jennifer Kyrnin, About's Guide to Web Design. If you do not understand this part of the code, you may want to consult her helps for learning CSS and HTML. Finally, to customise the month name, we need the following line:
print '<h1> %s %s </h1 >' %(current_month, current_yr)
Now that the basic layout is output, we can set up the calendar itself. A calendar, at its most basic point, is a table. So let's make a table in our HTML:
print ''' <table id="month" > <thead > <tr > <th class="weekend" >Sunday</th > <th >Monday</th > <th >Tuesday</th > <th >Wednesday</th > <th >Thursday</th > <th >Friday</th > <th class="weekend" >Saturday</th > </tr > </thead > <tbody > '''
Now our program will print our desired header with the current month and year. If you have used the command-line option mentioned earlier, here you should insert an if-else statement as follows:
if firstday == '0': print ''' <table id="month" > <thead > <tr > <th >Monday</th > <th >Tuesday</th > <th >Wednesday</th > <th >Thursday</th > <th >Friday</th > <th class="weekend" >Saturday</th > <th class="weekend" >Sunday</th > </tr > </thead > <tbody > ''' else: ## Here we assume a binary switch, a decision between '0' or not '0'; therefore, any non-zero argument will cause the calendar to start on Sunday. print ''' <table id="month" > <thead > <tr > <th class="weekend" >Sunday</th > <th >Monday</th > <th >Tuesday</th > <th >Wednesday</th > <th >Thursday</th > <th >Friday</th > <th class="weekend" >Saturday</th > </tr > </thead > <tbody > '''
Now we need to create the actual calendar. To get the actual calendar data, we need the calendar module's monthcalendar() method. This method takes two arguments: the year and the month of the desired calendar (both in integer form). It returns a list which contains lists of the dates of the month by week. So if we count the number of items in the returned value, we have the number of weeks in the given month.
month = calendar.monthcalendar(current_yr, current_no) nweeks = len(month)
Knowing the number of weeks in the month, we can create a for loop which counts through a range() from 0 to the number of weeks. As it does, it will print out the rest of the calendar.
for w in range(0,nweeks): week = month[w] print "<tr>" for x in xrange(0,7): day = week[x] if x == 5 or x == 6: classtype = 'weekend' else: classtype = 'day' if day == 0: classtype = 'previous' print '<td class="%s"></td>' %(classtype) elif day == current_day: print '<td class="%s"><strong>%s</strong></span><div class="%s"></div></td>' %(classtype, day, classtype) else: print '<td class="%s">%s</span><div class="%s"></div></td>' %(classtype, day, classtype) print "</tr>" print ''' </tbody> </table> </div> </body> </html>'''
We will discuss this code line-by-line on the next page.
After this range has been started, the dates of the week are culled from month according to the value of the counter and assigned to week. Then, a tabular row is created to hold the calendar dates.
A for loop then walks through the days of the week so they can be analyzed. The calendar module prints a '0' for every date in the table that does not have a valid value. A blank value would work better for our purposes so we print the bookends of tabular data without a value for those dates.
Next, if the day is the current one, we should highlight it somehow. Based on the td class today, the CSS of this page will cause the current date to be rendered against a dark background instead of the light background of the other dates.
Finally, if the date is a valid value and is not the current date, it is printed as tabular data. The exact color combinations for these are held in the CSS style preamble.
The last line of the first for loop closes the row. With the calendar printed our task is finished and we can close the HTML document.
As all of this code is in the main() function, do not forget to call it.
if __name__ == "__main__": main()
Just this simple calendar can be used in any way that needs a calendar representation. By hyperlinking the dates in the HTML, one can easily create a diary functionality. Alternatively, one can check against a diary file and then reflect which dates are taken by their color. Or, if one converts this program into a CGI script, one can have it generated on the fly.
Of course, this is just an overview of the calendar module's functionality. The documentation gives a fuller view.