1 ###############################
2 # Calendar printing functions #
3 ###############################
5 # Revision 2: uses funtions from built-in time module
7 # Import functions and variables from time module
8 from time
import gmtime
, localtime
, mktime
, asctime
, ctime
10 # Exception raised for bad input (with string parameter for details)
11 error
= 'calendar.error'
13 # Note when comparing these calendars to the ones printed by cal(1):
14 # My calendars have Monday as the first day of the week, and Sunday as
15 # the last! (I believe this is the European convention.)
17 # Constants for months referenced later
21 # Number of days per month (except for February in leap years)
22 mdays
= [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
24 # Full and abbreviated names of weekdays
25 day_name
= ['Monday', 'Tuesday', 'Wednesday', 'Thursday', \
26 'Friday', 'Saturday', 'Sunday']
27 day_abbr
= ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
29 # Full and abbreviated names of months (1-based arrays!!!)
30 month_name
= ['', 'January', 'February', 'March', 'April', \
31 'May', 'June', 'July', 'August', \
32 'September', 'October', 'November', 'December']
33 month_abbr
= [' ', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', \
34 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
36 # Return 1 for leap years, 0 for non-leap years
38 return year
% 4 == 0 and (year
% 100 <> 0 or year
% 400 == 0)
40 # Return number of leap years in range [y1, y2)
41 # Assume y1 <= y2 and no funny (non-leap century) years
43 return (y2
+3)/4 - (y1
+3)/4
45 # Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12), day (1-31)
46 def weekday(year
, month
, day
):
47 secs
= mktime((year
, month
, day
, 0, 0, 0, 0, 0, 0))
48 tuple = localtime(secs
)
51 # Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for year, month
52 def monthrange(year
, month
):
53 if not 1 <= month
<= 12: raise ValueError, 'bad month number'
54 day1
= weekday(year
, month
, 1)
55 ndays
= mdays
[month
] + (month
== February
and isleap(year
))
58 # Return a matrix representing a month's calendar
59 # Each row represents a week; days outside this month are zero
60 def _monthcalendar(year
, month
):
61 day1
, ndays
= monthrange(year
, month
)
66 row
= [0, 0, 0, 0, 0, 0, 0]
68 if 1 <= day
<= ndays
: row
[i
] = day
73 # Caching interface to _monthcalendar
75 def monthcalendar(year
, month
):
77 if _mc_cache
.has_key(key
):
80 _mc_cache
[key
] = ret
= _monthcalendar(year
, month
)
83 # Center a string in a field
84 def _center(str, width
):
87 return ' '*((n
+1)/2) + str + ' '*((n
)/2)
89 # XXX The following code knows that print separates items with space!
91 # Print a single week (no newline)
92 def prweek(week
, width
):
96 print _center(s
, width
),
98 # Return a header for a week
99 def weekheader(width
):
101 if width
>= 9: names
= day_name
102 else: names
= day_abbr
104 if str: str = str + ' '
105 str = str + _center(names
[i
%7][:width
], width
)
108 # Print a month's calendar
109 def prmonth(year
, month
, w
= 0, l
= 0):
112 print _center(month_name
[month
] + ' ' + `year`
, 7*(w
+1) - 1),
116 for week
in monthcalendar(year
, month
):
120 # Spacing of month columns
121 _colwidth
= 7*3 - 1 # Amount printed by prweek()
122 _spacing
= ' '*4 # Spaces between columns
124 # 3-column formatting for year calendars
125 def format3c(a
, b
, c
):
126 print _center(a
, _colwidth
),
128 print _center(b
, _colwidth
),
130 print _center(c
, _colwidth
)
132 # Print a year's calendar
134 header
= weekheader(2)
135 format3c('', `year`
, '')
136 for q
in range(January
, January
+12, 3):
138 format3c(month_name
[q
], month_name
[q
+1], month_name
[q
+2])
139 format3c(header
, header
, header
)
142 for month
in range(q
, q
+3):
143 cal
= monthcalendar(year
, month
)
144 if len(cal
) > height
: height
= len(cal
)
146 for i
in range(height
):