Skip to content

Commit d8c8010

Browse files
committed
Update calendar.py from CPython 3.8.5
1 parent 446bf76 commit d8c8010

File tree

1 file changed

+87
-30
lines changed

1 file changed

+87
-30
lines changed

Lib/calendar.py

Lines changed: 87 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ def leapdays(y1, y2):
111111

112112

113113
def weekday(year, month, day):
114-
"""Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12),
115-
day (1-31)."""
114+
"""Return weekday (0-6 ~ Mon-Sun) for year, month (1-12), day (1-31)."""
115+
if not datetime.MINYEAR <= year <= datetime.MAXYEAR:
116+
year = 2000 + year % 400
116117
return datetime.date(year, month, day).weekday()
117118

118119

@@ -126,6 +127,24 @@ def monthrange(year, month):
126127
return day1, ndays
127128

128129

130+
def _monthlen(year, month):
131+
return mdays[month] + (month == February and isleap(year))
132+
133+
134+
def _prevmonth(year, month):
135+
if month == 1:
136+
return year-1, 12
137+
else:
138+
return year, month-1
139+
140+
141+
def _nextmonth(year, month):
142+
if month == 12:
143+
return year+1, 1
144+
else:
145+
return year, month+1
146+
147+
129148
class Calendar(object):
130149
"""
131150
Base calendar class. This class doesn't do any formatting. It simply
@@ -157,20 +176,20 @@ def itermonthdates(self, year, month):
157176
values and will always iterate through complete weeks, so it will yield
158177
dates outside the specified month.
159178
"""
160-
date = datetime.date(year, month, 1)
161-
# Go back to the beginning of the week
162-
days = (date.weekday() - self.firstweekday) % 7
163-
date -= datetime.timedelta(days=days)
164-
oneday = datetime.timedelta(days=1)
165-
while True:
166-
yield date
167-
try:
168-
date += oneday
169-
except OverflowError:
170-
# Adding one day could fail after datetime.MAXYEAR
171-
break
172-
if date.month != month and date.weekday() == self.firstweekday:
173-
break
179+
for y, m, d in self.itermonthdays3(year, month):
180+
yield datetime.date(y, m, d)
181+
182+
def itermonthdays(self, year, month):
183+
"""
184+
Like itermonthdates(), but will yield day numbers. For days outside
185+
the specified month the day number is 0.
186+
"""
187+
day1, ndays = monthrange(year, month)
188+
days_before = (day1 - self.firstweekday) % 7
189+
yield from repeat(0, days_before)
190+
yield from range(1, ndays + 1)
191+
days_after = (self.firstweekday - day1 - ndays) % 7
192+
yield from repeat(0, days_after)
174193

175194
def itermonthdays2(self, year, month):
176195
"""
@@ -180,17 +199,31 @@ def itermonthdays2(self, year, month):
180199
for i, d in enumerate(self.itermonthdays(year, month), self.firstweekday):
181200
yield d, i % 7
182201

183-
def itermonthdays(self, year, month):
202+
def itermonthdays3(self, year, month):
184203
"""
185-
Like itermonthdates(), but will yield day numbers. For days outside
186-
the specified month the day number is 0.
204+
Like itermonthdates(), but will yield (year, month, day) tuples. Can be
205+
used for dates outside of datetime.date range.
187206
"""
188207
day1, ndays = monthrange(year, month)
189208
days_before = (day1 - self.firstweekday) % 7
190-
yield from repeat(0, days_before)
191-
yield from range(1, ndays + 1)
192209
days_after = (self.firstweekday - day1 - ndays) % 7
193-
yield from repeat(0, days_after)
210+
y, m = _prevmonth(year, month)
211+
end = _monthlen(y, m) + 1
212+
for d in range(end-days_before, end):
213+
yield y, m, d
214+
for d in range(1, ndays + 1):
215+
yield year, month, d
216+
y, m = _nextmonth(year, month)
217+
for d in range(1, days_after + 1):
218+
yield y, m, d
219+
220+
def itermonthdays4(self, year, month):
221+
"""
222+
Like itermonthdates(), but will yield (year, month, day, day_of_week) tuples.
223+
Can be used for dates outside of datetime.date range.
224+
"""
225+
for i, (y, m, d) in enumerate(self.itermonthdays3(year, month)):
226+
yield y, m, d, (self.firstweekday + i) % 7
194227

195228
def monthdatescalendar(self, year, month):
196229
"""
@@ -267,7 +300,7 @@ def prweek(self, theweek, width):
267300
"""
268301
Print a single week (no newline).
269302
"""
270-
print(self.formatweek(theweek, width), end=' ')
303+
print(self.formatweek(theweek, width), end='')
271304

272305
def formatday(self, day, weekday, width):
273306
"""
@@ -371,7 +404,7 @@ def formatyear(self, theyear, w=2, l=1, c=6, m=3):
371404

372405
def pryear(self, theyear, w=0, l=0, c=6, m=3):
373406
"""Print a year's calendar."""
374-
print(self.formatyear(theyear, w, l, c, m))
407+
print(self.formatyear(theyear, w, l, c, m), end='')
375408

376409

377410
class HTMLCalendar(Calendar):
@@ -382,12 +415,31 @@ class HTMLCalendar(Calendar):
382415
# CSS classes for the day <td>s
383416
cssclasses = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
384417

418+
# CSS classes for the day <th>s
419+
cssclasses_weekday_head = cssclasses
420+
421+
# CSS class for the days before and after current month
422+
cssclass_noday = "noday"
423+
424+
# CSS class for the month's head
425+
cssclass_month_head = "month"
426+
427+
# CSS class for the month
428+
cssclass_month = "month"
429+
430+
# CSS class for the year's table head
431+
cssclass_year_head = "year"
432+
433+
# CSS class for the whole year table
434+
cssclass_year = "year"
435+
385436
def formatday(self, day, weekday):
386437
"""
387438
Return a day as a table cell.
388439
"""
389440
if day == 0:
390-
return '<td class="noday">&nbsp;</td>' # day outside month
441+
# day outside month
442+
return '<td class="%s">&nbsp;</td>' % self.cssclass_noday
391443
else:
392444
return '<td class="%s">%d</td>' % (self.cssclasses[weekday], day)
393445

@@ -402,7 +454,8 @@ def formatweekday(self, day):
402454
"""
403455
Return a weekday name as a table header.
404456
"""
405-
return '<th class="%s">%s</th>' % (self.cssclasses[day], day_abbr[day])
457+
return '<th class="%s">%s</th>' % (
458+
self.cssclasses_weekday_head[day], day_abbr[day])
406459

407460
def formatweekheader(self):
408461
"""
@@ -419,15 +472,17 @@ def formatmonthname(self, theyear, themonth, withyear=True):
419472
s = '%s %s' % (month_name[themonth], theyear)
420473
else:
421474
s = '%s' % month_name[themonth]
422-
return '<tr><th colspan="7" class="month">%s</th></tr>' % s
475+
return '<tr><th colspan="7" class="%s">%s</th></tr>' % (
476+
self.cssclass_month_head, s)
423477

424478
def formatmonth(self, theyear, themonth, withyear=True):
425479
"""
426480
Return a formatted month as a table.
427481
"""
428482
v = []
429483
a = v.append
430-
a('<table border="0" cellpadding="0" cellspacing="0" class="month">')
484+
a('<table border="0" cellpadding="0" cellspacing="0" class="%s">' % (
485+
self.cssclass_month))
431486
a('\n')
432487
a(self.formatmonthname(theyear, themonth, withyear=withyear))
433488
a('\n')
@@ -447,9 +502,11 @@ def formatyear(self, theyear, width=3):
447502
v = []
448503
a = v.append
449504
width = max(width, 1)
450-
a('<table border="0" cellpadding="0" cellspacing="0" class="year">')
505+
a('<table border="0" cellpadding="0" cellspacing="0" class="%s">' %
506+
self.cssclass_year)
451507
a('\n')
452-
a('<tr><th colspan="%d" class="year">%s</th></tr>' % (width, theyear))
508+
a('<tr><th colspan="%d" class="%s">%s</th></tr>' % (
509+
width, self.cssclass_year_head, theyear))
453510
for i in range(January, January+12, width):
454511
# months in this row
455512
months = range(i, min(i+width, 13))

0 commit comments

Comments
 (0)