Commit 957b7569 authored by Alexander Belopolsky's avatar Alexander Belopolsky

Issue #28253: Fixed calendar functions for extreme months: 0001-01 and 9999-12.

Methods itermonthdays() and itermonthdays2() are reimplemented so that they
don't call itermonthdates() which can cause datetime.date under/overflow.
parent 4cefe74a
...@@ -8,6 +8,7 @@ set the first day of the week (0=Monday, 6=Sunday).""" ...@@ -8,6 +8,7 @@ set the first day of the week (0=Monday, 6=Sunday)."""
import sys import sys
import datetime import datetime
import locale as _locale import locale as _locale
from itertools import repeat
__all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday", __all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
"firstweekday", "isleap", "leapdays", "weekday", "monthrange", "firstweekday", "isleap", "leapdays", "weekday", "monthrange",
...@@ -174,22 +175,20 @@ class Calendar(object): ...@@ -174,22 +175,20 @@ class Calendar(object):
Like itermonthdates(), but will yield (day number, weekday number) Like itermonthdates(), but will yield (day number, weekday number)
tuples. For days outside the specified month the day number is 0. tuples. For days outside the specified month the day number is 0.
""" """
for date in self.itermonthdates(year, month): for i, d in enumerate(self.itermonthdays(year, month), self.firstweekday):
if date.month != month: yield d, i % 7
yield (0, date.weekday())
else:
yield (date.day, date.weekday())
def itermonthdays(self, year, month): def itermonthdays(self, year, month):
""" """
Like itermonthdates(), but will yield day numbers. For days outside Like itermonthdates(), but will yield day numbers. For days outside
the specified month the day number is 0. the specified month the day number is 0.
""" """
for date in self.itermonthdates(year, month): day1, ndays = monthrange(year, month)
if date.month != month: days_before = (day1 - self.firstweekday) % 7
yield 0 yield from repeat(0, days_before)
else: yield from range(1, ndays + 1)
yield date.day days_after = (self.firstweekday - day1 - ndays) % 7
yield from repeat(0, days_after)
def monthdatescalendar(self, year, month): def monthdatescalendar(self, year, month):
""" """
......
...@@ -502,6 +502,27 @@ class CalendarTestCase(unittest.TestCase): ...@@ -502,6 +502,27 @@ class CalendarTestCase(unittest.TestCase):
# see #15421 # see #15421
list(calendar.Calendar().itermonthdates(datetime.MAXYEAR, 12)) list(calendar.Calendar().itermonthdates(datetime.MAXYEAR, 12))
def test_itermonthdays(self):
for firstweekday in range(7):
cal = calendar.Calendar(firstweekday)
# Test the extremes, see #28253 and #26650
for y, m in [(1, 1), (9999, 12)]:
days = list(cal.itermonthdays(y, m))
self.assertIn(len(days), (35, 42))
# Test a short month
cal = calendar.Calendar(firstweekday=3)
days = list(cal.itermonthdays(2001, 2))
self.assertEqual(days, list(range(1, 29)))
def test_itermonthdays2(self):
for firstweekday in range(7):
cal = calendar.Calendar(firstweekday)
# Test the extremes, see #28253 and #26650
for y, m in [(1, 1), (9999, 12)]:
days = list(cal.itermonthdays2(y, m))
self.assertEqual(days[0][1], firstweekday)
self.assertEqual(days[-1][1], (firstweekday - 1) % 7)
class MonthCalendarTestCase(unittest.TestCase): class MonthCalendarTestCase(unittest.TestCase):
def setUp(self): def setUp(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment