diff -r ac176a69d188 Lib/_strptime.py --- a/Lib/_strptime.py Sun Dec 28 22:14:23 2014 -0600 +++ b/Lib/_strptime.py Wed Dec 31 19:26:40 2014 +0200 @@ -18,7 +18,8 @@ from re import IGNORECASE from re import escape as re_escape from datetime import (date as datetime_date, timedelta as datetime_timedelta, - timezone as datetime_timezone) + timezone as datetime_timezone, + _is_leap) try: from _thread import allocate_lock as _thread_allocate_lock except ImportError: @@ -348,9 +349,9 @@ def _strptime(data_string, format="%a %b # though week_of_year = -1 week_of_year_start = -1 - # weekday and julian defaulted to -1 so as to signal need to calculate + # weekday and julian defaulted to None so as to signal need to calculate # values - weekday = julian = -1 + weekday = julian = None found_dict = found.groupdict() for group_key in found_dict.keys(): # Directives not explicitly handled below: @@ -452,14 +453,18 @@ def _strptime(data_string, format="%a %b year = 1900 # If we know the week of the year and what day of that week, we can figure # out the Julian day of the year. - if julian == -1 and week_of_year != -1 and weekday != -1: + if julian is None and week_of_year != -1 and weekday is not None: week_starts_Mon = True if week_of_year_start == 0 else False julian = _calc_julian_from_U_or_W(year, week_of_year, weekday, week_starts_Mon) + if julian <= 0: + raise ValueError('weekday before the start of the year') + if julian > 365 + _is_leap(year): + raise ValueError('weekday after the end of the year') # Cannot pre-calculate datetime_date() since can change in Julian # calculation and thus could have different value for the day of the week # calculation. - if julian == -1: + if julian is None: # Need to add 1 to result since first day of the year is 1, not 0. julian = datetime_date(year, month, day).toordinal() - \ datetime_date(year, 1, 1).toordinal() + 1 @@ -469,7 +474,7 @@ def _strptime(data_string, format="%a %b year = datetime_result.year month = datetime_result.month day = datetime_result.day - if weekday == -1: + if weekday is None: weekday = datetime_date(year, month, day).weekday() # Add timezone info tzname = found_dict.get("Z") diff -r ac176a69d188 Lib/datetime.py --- a/Lib/datetime.py Sun Dec 28 22:14:23 2014 -0600 +++ b/Lib/datetime.py Wed Dec 31 19:26:40 2014 +0200 @@ -2143,7 +2143,7 @@ else: _check_date_fields, _check_int_field, _check_time_fields, _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror, _date_class, _days_before_month, _days_before_year, _days_in_month, - _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd, + _format_time, _isoweek1monday, _math, _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord) # XXX Since import * above excludes names that start with _, # docstring does not get overwritten. In the future, it may be diff -r ac176a69d188 Lib/test/test_strptime.py --- a/Lib/test/test_strptime.py Sun Dec 28 22:14:23 2014 -0600 +++ b/Lib/test/test_strptime.py Wed Dec 31 19:26:40 2014 +0200 @@ -494,6 +494,33 @@ class CalculationTests(unittest.TestCase test_helper((2006, 12, 31), "Last Sunday of 2006") test_helper((2006, 12, 24), "Second to last Sunday of 2006") + def test_ranges(self): + def check(value, format, result): + self.assertEqual(_strptime._strptime_time(value, format)[:], result) + def check_invalid(value, format): + with self.assertRaises(ValueError): + _strptime._strptime_time(value, format) + + check('2015 1 6', '%Y %W %w', (2015, 1, 10, 0, 0, 0, 5, 10, -1)) + check_invalid('2015 1 7', '%Y %W %w') + check('2015 0 4', '%Y %U %w', (2015, 1, 1, 0, 0, 0, 3, 1, -1)) + check('2015 0 4', '%Y %W %w', (2015, 1, 1, 0, 0, 0, 3, 1, -1)) + check('2015 52 4', '%Y %U %w', (2015, 12, 31, 0, 0, 0, 3, 365, -1)) + check('2015 52 4', '%Y %W %w', (2015, 12, 31, 0, 0, 0, 3, 365, -1)) + check_invalid('2015 0 2', '%Y %U %w') + check_invalid('2015 0 2', '%Y %W %w') + check_invalid('2015 52 5', '%Y %U %w') + check_invalid('2015 52 5', '%Y %W %w') + check('2016 0 5', '%Y %U %w', (2016, 1, 1, 0, 0, 0, 4, 1, -1)) + check('2016 0 5', '%Y %W %w', (2016, 1, 1, 0, 0, 0, 4, 1, -1)) + check('2016 52 6', '%Y %U %w', (2016, 12, 31, 0, 0, 0, 5, 366, -1)) + check('2016 52 6', '%Y %W %w', (2016, 12, 31, 0, 0, 0, 5, 366, -1)) + check_invalid('2016 0 4', '%Y %U %w') + check_invalid('2016 0 4', '%Y %W %w') + check_invalid('2016 53 0', '%Y %U %w') + check_invalid('2016 53 0', '%Y %W %w') + check_invalid('2016 54 0', '%Y %W %w') + class CacheTests(unittest.TestCase): """Test that caching works properly."""