Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ad3bc44

Browse files
author
Skip Montanaro
committed
patches from David Goodger. Closes patch 101085.
* deletes cache * adds firstweekday and setfirstweekday functions that allow user to control which day of the week is first when displaying calendars * adds month, week, calendar functions that return their results instead of printing them * adds symbolic constants MONDAY, ..., SUNDAY so users need not remember the ordinal values of the weekdays
1 parent 3cdb576 commit ad3bc44

1 file changed

Lines changed: 104 additions & 69 deletions

File tree

Lib/calendar.py

Lines changed: 104 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
"""Calendar printing functions"""
1+
"""Calendar printing functions
2+
3+
Note when comparing these calendars to the ones printed by cal(1): By
4+
default, these calendars have Monday as the first day of the week, and
5+
Sunday as the last (the European convention). Use setfirstweekday() to
6+
set the first day of the week (0=Monday, 6=Sunday)."""
27

38
# Revision 2: uses functions from built-in time module
49

@@ -8,10 +13,6 @@
813
# Exception raised for bad input (with string parameter for details)
914
error = ValueError
1015

11-
# Note when comparing these calendars to the ones printed by cal(1):
12-
# My calendars have Monday as the first day of the week, and Sunday as
13-
# the last! (I believe this is the European convention.)
14-
1516
# Constants for months referenced later
1617
January = 1
1718
February = 2
@@ -31,35 +32,54 @@
3132
month_abbr = [' ', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
3233
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
3334

35+
# Constants for weekdays
36+
(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)
37+
38+
_firstweekday = 0 # 0 = Monday, 6 = Sunday
39+
40+
def firstweekday():
41+
return _firstweekday
42+
43+
def setfirstweekday(weekday):
44+
"""Set weekday (Monday=0, Sunday=6) to start each week."""
45+
global _firstweekday
46+
if not MONDAY <= weekday <= SUNDAY:
47+
raise ValueError, \
48+
'bad weekday number; must be 0 (Monday) to 6 (Sunday)'
49+
_firstweekday = weekday
50+
3451
def isleap(year):
3552
"""Return 1 for leap years, 0 for non-leap years."""
3653
return year % 4 == 0 and (year % 100 <> 0 or year % 400 == 0)
3754

3855
def leapdays(y1, y2):
3956
"""Return number of leap years in range [y1, y2).
40-
Assume y1 <= y2 and no funny (non-leap century) years."""
57+
Assume y1 <= y2 and no funny (non-leap century) years."""
4158
return (y2+3)/4 - (y1+3)/4
4259

4360
def weekday(year, month, day):
44-
"""Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12), day (1-31)."""
61+
"""Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12),
62+
day (1-31)."""
4563
secs = mktime((year, month, day, 0, 0, 0, 0, 0, 0))
4664
tuple = localtime(secs)
4765
return tuple[6]
4866

4967
def monthrange(year, month):
50-
"""Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for year, month."""
51-
if not 1 <= month <= 12: raise ValueError, 'bad month number'
68+
"""Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for
69+
year, month."""
70+
if not 1 <= month <= 12:
71+
raise ValueError, 'bad month number'
5272
day1 = weekday(year, month, 1)
5373
ndays = mdays[month] + (month == February and isleap(year))
5474
return day1, ndays
5575

56-
def _monthcalendar(year, month):
76+
def monthcalendar(year, month):
5777
"""Return a matrix representing a month's calendar.
58-
Each row represents a week; days outside this month are zero."""
78+
Each row represents a week; days outside this month are zero."""
5979
day1, ndays = monthrange(year, month)
6080
rows = []
6181
r7 = range(7)
62-
day = 1 - day1
82+
day = (_firstweekday - day1 + 6) % 7 - 5 # for leading 0's in first week
6383
while day <= ndays:
6484
row = [0, 0, 0, 0, 0, 0, 0]
6585
for i in r7:
@@ -68,87 +88,102 @@ def _monthcalendar(year, month):
6888
rows.append(row)
6989
return rows
7090

71-
_mc_cache = {}
72-
def monthcalendar(year, month):
73-
"""Caching interface to _monthcalendar."""
74-
key = (year, month)
75-
if _mc_cache.has_key(key):
76-
return _mc_cache[key]
77-
else:
78-
_mc_cache[key] = ret = _monthcalendar(year, month)
79-
return ret
80-
8191
def _center(str, width):
8292
"""Center a string in a field."""
8393
n = width - len(str)
84-
if n <= 0: return str
94+
if n <= 0:
95+
return str
8596
return ' '*((n+1)/2) + str + ' '*((n)/2)
8697

87-
# XXX The following code knows that print separates items with space!
88-
89-
def prweek(week, width):
98+
def prweek(theweek, width):
9099
"""Print a single week (no newline)."""
91-
for day in week:
92-
if day == 0: s = ''
93-
else: s = `day`
94-
print _center(s, width),
100+
print week(theweek, width),
101+
102+
def week(theweek, width):
103+
"""Returns a single week in a string (no newline)."""
104+
days = []
105+
for day in theweek:
106+
if day == 0:
107+
s = ''
108+
else:
109+
s = '%2i' % day # right-align single-digit days
110+
days.append(_center(s, width))
111+
return ' '.join(days)
95112

96113
def weekheader(width):
97114
"""Return a header for a week."""
98-
str = ''
99-
if width >= 9: names = day_name
100-
else: names = day_abbr
101-
for i in range(7):
102-
if str: str = str + ' '
103-
str = str + _center(names[i%7][:width], width)
104-
return str
105-
106-
def prmonth(year, month, w = 0, l = 0):
115+
if width >= 9:
116+
names = day_name
117+
else:
118+
names = day_abbr
119+
days = []
120+
for i in range(_firstweekday, _firstweekday + 7):
121+
days.append(_center(names[i%7][:width], width))
122+
return ' '.join(days)
123+
124+
def prmonth(theyear, themonth, w=0, l=0):
107125
"""Print a month's calendar."""
126+
print month(theyear, themonth, w, l),
127+
128+
def month(theyear, themonth, w=0, l=0):
129+
"""Return a month's calendar string (multi-line)."""
108130
w = max(2, w)
109131
l = max(1, l)
110-
print _center(month_name[month] + ' ' + `year`, 7*(w+1) - 1),
111-
print '\n'*l,
112-
print weekheader(w),
113-
print '\n'*l,
114-
for week in monthcalendar(year, month):
115-
prweek(week, w)
116-
print '\n'*l,
117-
118-
# Spacing of month columns
132+
s = (_center(month_name[themonth] + ' ' + `theyear`,
133+
7 * (w + 1) - 1).rstrip() +
134+
'\n' * l + weekheader(w).rstrip() + '\n' * l)
135+
for aweek in monthcalendar(theyear, themonth):
136+
s = s + week(aweek, w).rstrip() + '\n' * l
137+
return s[:-l] + '\n'
138+
139+
# Spacing of month columns for 3-column year calendar
119140
_colwidth = 7*3 - 1 # Amount printed by prweek()
120-
_spacing = ' '*4 # Spaces between columns
141+
_spacing = 6 # Number of spaces between columns
121142

122-
def format3c(a, b, c):
123-
"""3-column formatting for year calendars"""
124-
print _center(a, _colwidth),
125-
print _spacing,
126-
print _center(b, _colwidth),
127-
print _spacing,
128-
print _center(c, _colwidth)
143+
def format3c(a, b, c, colwidth=_colwidth, spacing=_spacing):
144+
"""Prints 3-column formatting for year calendars"""
145+
print format3cstring(a, b, c, colwidth, spacing)
129146

130-
def prcal(year):
147+
def format3cstring(a, b, c, colwidth=_colwidth, spacing=_spacing):
148+
"""Returns a string formatted from 3 strings, centered within 3 columns."""
149+
return (_center(a, colwidth) + ' ' * spacing + _center(b, colwidth) +
150+
' ' * spacing + _center(c, colwidth))
151+
152+
def prcal(year, w=0, l=0, c=_spacing):
131153
"""Print a year's calendar."""
132-
header = weekheader(2)
133-
format3c('', `year`, '')
154+
print calendar(year, w, l, c),
155+
156+
def calendar(year, w=0, l=0, c=_spacing):
157+
"""Returns a year's calendar as a multi-line string."""
158+
w = max(2, w)
159+
l = max(1, l)
160+
c = max(2, c)
161+
colwidth = (w + 1) * 7 - 1
162+
s = _center(`year`, colwidth * 3 + c * 2).rstrip() + '\n' * l
163+
header = weekheader(w)
164+
header = format3cstring(header, header, header, colwidth, c).rstrip()
134165
for q in range(January, January+12, 3):
135-
print
136-
format3c(month_name[q], month_name[q+1], month_name[q+2])
137-
format3c(header, header, header)
166+
s = (s + '\n' * l +
167+
format3cstring(month_name[q], month_name[q+1], month_name[q+2],
168+
colwidth, c).rstrip() +
169+
'\n' * l + header + '\n' * l)
138170
data = []
139171
height = 0
140-
for month in range(q, q+3):
141-
cal = monthcalendar(year, month)
142-
if len(cal) > height: height = len(cal)
172+
for amonth in range(q, q + 3):
173+
cal = monthcalendar(year, amonth)
174+
if len(cal) > height:
175+
height = len(cal)
143176
data.append(cal)
144177
for i in range(height):
178+
weeks = []
145179
for cal in data:
146180
if i >= len(cal):
147-
print ' '*_colwidth,
181+
weeks.append('')
148182
else:
149-
prweek(cal[i], 2)
150-
print _spacing,
151-
print
183+
weeks.append(week(cal[i], w))
184+
s = s + format3cstring(weeks[0], weeks[1], weeks[2],
185+
colwidth, c).rstrip() + '\n' * l
186+
return s[:-l] + '\n'
152187

153188
EPOCH = 1970
154189
def timegm(tuple):

0 commit comments

Comments
 (0)