diff -r 0e56d79fa2ab Lib/_strptime.py --- a/Lib/_strptime.py Tue May 24 18:29:46 2011 +0200 +++ b/Lib/_strptime.py Thu May 26 17:31:52 2011 -0500 @@ -194,6 +194,7 @@ 'd': r"(?P3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])", 'f': r"(?P[0-9]{1,6})", 'H': r"(?P2[0-3]|[0-1]\d|\d)", + 'G': r"(?P\d\d\d\d)", 'I': r"(?P1[0-2]|0[1-9]|[1-9])", 'j': r"(?P36[0-6]|3[0-5]\d|[1-2]\d\d|0[1-9]\d|00[1-9]|[1-9]\d|0[1-9]|[1-9])", 'm': r"(?P1[0-2]|0[1-9]|[1-9])", @@ -201,6 +202,8 @@ 'S': r"(?P6[0-1]|[0-5]\d|\d)", 'U': r"(?P5[0-3]|[0-4]\d|\d)", 'w': r"(?P[0-6])", + 'u': r"(?P[1-7])", + 'V': r"(?P5[0-3]|0[1-9]|[1-4]\d|\d)", # W is set below by using 'U' 'y': r"(?P\d\d)", #XXX: Does 'Y' need to worry about having less or more than @@ -294,6 +297,21 @@ days_to_week = week_0_length + (7 * (week_of_year - 1)) return 1 + days_to_week + day_of_week +def _calc_julian_from_V(iso_year, iso_week, iso_weekday): + """Calculate the Julian day based on the ISO 8601 year, week, and weekday. + ISO weeks start on Mondays, with week 01 being the week containing 4 Jan. + ISO week days range from 1 (Monday) to 7 (Sunday). + """ + correction = datetime_date(iso_year,1,4).isoweekday() + 3 + ordinal = (iso_week * 7) + iso_weekday - correction + # ordinal may be negative or 0 now, which means the date is in the previous + # calendar year + if ordinal < 1: + ordinal += datetime_date(iso_year,1,1).toordinal() + ordinal -= datetime_date(iso_year-1,1,1).toordinal() + return iso_year - 1, ordinal + else: + return iso_year, ordinal def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): """Return a 2-tuple consisting of a time struct and an int containing @@ -348,6 +366,9 @@ # though week_of_year = -1 week_of_year_start = -1 + iso_weekday = -1 + iso_week = -1 + iso_year = -1 # weekday and julian defaulted to -1 so as to signal need to calculate # values weekday = julian = -1 @@ -369,6 +390,8 @@ year += 1900 elif group_key == 'Y': year = int(found_dict['Y']) + elif group_key == 'G': + iso_year = int(found_dict['G']) elif group_key == 'm': month = int(found_dict['m']) elif group_key == 'B': @@ -414,6 +437,14 @@ weekday = 6 else: weekday -= 1 + iso_weekday = weekday + 1 + elif group_key == 'u': + iso_weekday = int(found_dict['u']) + weekday = iso_weekday % 7 + if weekday == 0: + weekday = 6 + else: + weekday -=1 elif group_key == 'j': julian = int(found_dict['j']) elif group_key in ('U', 'W'): @@ -424,6 +455,8 @@ else: # W starts week on Monday. week_of_year_start = 0 + elif group_key == 'V': + iso_week = int(found_dict['V']) elif group_key == 'z': z = found_dict['z'] tzoffset = int(z[1:3]) * 60 + int(z[3:5]) @@ -450,6 +483,9 @@ 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) + elif julian == -1 and iso_week != -1 and iso_weekday != -1: + iso_year = year if iso_year == -1 else iso_year + year, julian = _calc_julian_from_V(iso_year, iso_week, iso_weekday) # Cannot pre-calculate datetime_date() since can change in Julian # calculation and thus could have different value for the day of the week # calculation. diff -r 0e56d79fa2ab Lib/test/test_strptime.py --- a/Lib/test/test_strptime.py Tue May 24 18:29:46 2011 +0200 +++ b/Lib/test/test_strptime.py Thu May 26 17:31:52 2011 -0500 @@ -155,8 +155,8 @@ "'%s' using '%s'; group 'a' = '%s', group 'b' = %s'" % (found.string, found.re.pattern, found.group('a'), found.group('b'))) - for directive in ('a','A','b','B','c','d','H','I','j','m','M','p','S', - 'U','w','W','x','X','y','Y','Z','%'): + for directive in ('a','A','b','B','c','d','G','H','I','j','m','M','p', + 'S','u','U','V','w','W','x','X','y','Y','Z','%'): compiled = self.time_re.compile("%" + directive) found = compiled.match(time.strftime("%" + directive)) self.assertTrue(found, "Matching failed on '%s' using '%s' regex" % @@ -282,7 +282,7 @@ def test_weekday(self): # Test weekday directives - for directive in ('A', 'a', 'w'): + for directive in ('A', 'a', 'w', 'u'): self.helper(directive,6) def test_julian(self): @@ -443,8 +443,11 @@ # Should be able to infer date if given year, week of year (%U or %W) # and day of the week def test_helper(ymd_tuple, test_reason): - for directive in ('W', 'U'): - format_string = "%%Y %%%s %%w" % directive + for directive in ('W', 'U', 'V'): + if directive != 'V': + format_string = "%%Y %%%s %%w" % directive + else: + format_string = "%%G %%%s %%u" % directive dt_date = datetime_date(*ymd_tuple) strp_input = dt_date.strftime(format_string) strp_output = _strptime._strptime_time(strp_input, format_string)