From 9c183d224781d0ab655f2e8815ac5f504ab7bc26 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 18 Oct 2004 01:56:17 +0000 Subject: [PATCH] Add support for using %U and %W in strptime when year and day of the week are also specified. Closes bug #1045381. --- Doc/lib/libtime.tex | 8 ++++++-- Lib/_strptime.py | 39 +++++++++++++++++++++++++++++++++++++-- Lib/test/test_strptime.py | 24 ++++++++++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/Doc/lib/libtime.tex b/Doc/lib/libtime.tex index 0929c179d5df..5d8fe639e3bb 100644 --- a/Doc/lib/libtime.tex +++ b/Doc/lib/libtime.tex @@ -235,11 +235,11 @@ specification, and are replaced by the indicated characters in the \lineiii{\%S}{Second as a decimal number [00,61].}{(1)} \lineiii{\%U}{Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year - preceding the first Sunday are considered to be in week 0.}{} + preceding the first Sunday are considered to be in week 0.}{(2)} \lineiii{\%w}{Weekday as a decimal number [0(Sunday),6].}{} \lineiii{\%W}{Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year - preceding the first Monday are considered to be in week 0.}{} + preceding the first Monday are considered to be in week 0.}{(2)} \lineiii{\%x}{Locale's appropriate date representation.}{} \lineiii{\%X}{Locale's appropriate time representation.}{} \lineiii{\%y}{Year without century as a decimal number [00,99].}{} @@ -255,6 +255,10 @@ Notes: \item[(1)] The range really is \code{0} to \code{61}; this accounts for leap seconds and the (very rare) double leap seconds. + \item[(2)] + When used with the \function{strptime()} function, \code{\%U} and \code{\%W} + are only used in calculations when the day of the week and the year are + specified. \end{description} Here is an example, a format for dates compatible with that specified diff --git a/Lib/_strptime.py b/Lib/_strptime.py index cc578305ad98..d3959ae754dd 100644 --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -311,7 +311,7 @@ class TimeRE(dict): # W is set below by using 'U' 'y': r"(?P\d\d)", 'Y': r"(?P\d\d\d\d)"}) - base.__setitem__('W', base.__getitem__('U')) + base.__setitem__('W', base.__getitem__('U').replace('U', 'W')) if locale_time: self.locale_time = locale_time else: @@ -431,6 +431,8 @@ def strptime(data_string, format="%a %b %d %H:%M:%S %Y"): month = day = 1 hour = minute = second = 0 tz = -1 + week_of_year = -1 + week_of_year_start = -1 # weekday and julian defaulted to -1 so as to signal need to calculate values weekday = julian = -1 found_dict = found.groupdict() @@ -490,6 +492,14 @@ def strptime(data_string, format="%a %b %d %H:%M:%S %Y"): weekday -= 1 elif group_key == 'j': julian = int(found_dict['j']) + elif group_key in ('U', 'W'): + week_of_year = int(found_dict[group_key]) + if group_key == 'U': + # U starts week on Sunday + week_of_year_start = 6 + else: + # W starts week on Monday + week_of_year_start = 0 elif group_key == 'Z': # Since -1 is default value only need to worry about setting tz if # it can be something other than -1. @@ -505,7 +515,32 @@ def strptime(data_string, format="%a %b %d %H:%M:%S %Y"): elif time.daylight and \ locale_time.timezone[3].lower() == found_zone: tz = 1 - + # If we know the week of the year and what day of that week, we can figure + # out the Julian day of the year + # Calculations below assume 0 is a Monday + if julian == -1 and week_of_year != -1 and weekday != -1 and year != -1: + # Adjust for U directive so that calculations are not dependent on + # directive used to figure out week of year + if weekday == 6 and week_of_year_start == 6: + week_of_year -= 1 + # For some reason when Dec 31 falls on a Monday the week of the year is + # off by a week; verified on both OS X and Solaris. + elif weekday == 0 and week_of_year_start == 6 and week_of_year >= 52: + week_of_year += 1 + # Calculate how many days in week 0 + first_weekday = datetime_date(year, 1, 1).weekday() + preceeding_days = 7 - first_weekday + if preceeding_days == 7: + preceeding_days = 0 + # If in week 0, then just figure out how many days from Jan 1 to day of + # week specified, else calculate by multiplying week of year by 7, + # adding in days in week 0, and the number of days from Monday to the + # day of the week + if not week_of_year: + julian = 1 + weekday - first_weekday + else: + days_to_week = preceeding_days + (7 * (week_of_year - 1)) + julian = 1 + days_to_week + 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 --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py index 869954c1ec58..09b59212d6b3 100644 --- a/Lib/test/test_strptime.py +++ b/Lib/test/test_strptime.py @@ -6,6 +6,7 @@ import locale import re import sys from test import test_support +from datetime import date as datetime_date import _strptime @@ -450,6 +451,29 @@ class CalculationTests(unittest.TestCase): "Calculation of day of the week failed;" "%s != %s" % (result.tm_wday, self.time_tuple.tm_wday)) + def test_week_of_year_and_day_of_week_calculation(self): + # 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 + strp_input = datetime_date(*ymd_tuple).strftime(format_string) + strp_output = _strptime.strptime(strp_input, format_string) + self.failUnless(strp_output[:3] == ymd_tuple, + "%s(%s) test failed w/ '%s': %s != %s" % + (test_reason, directive, strp_input, + strp_output[:3], ymd_tuple[:3])) + test_helper((1901, 1, 3), "week 0") + test_helper((1901, 1, 8), "common case") + test_helper((1901, 1, 13), "day on Sunday") + test_helper((1901, 1, 14), "day on Monday") + test_helper((1905, 1, 1), "Jan 1 on Sunday") + test_helper((1906, 1, 1), "Jan 1 on Monday") + test_helper((1905, 12, 31), "Dec 31 on Sunday") + test_helper((1906, 12, 31), "Dec 31 on Monday") + + + class CacheTests(unittest.TestCase): """Test that caching works properly.""" diff --git a/Misc/NEWS b/Misc/NEWS index 15b6b7f7b129..f598834bf13b 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,6 +53,9 @@ Extension modules Library ------- +- Bug #1045381: strptime() now uses %U and %W for date calculations if the year + and day of the week are also specified. + - Bug #1039270: Locale data is now escaped for regex metacharacters. - Bug #807871: Fix tkMessageBox.askyesno result. -- 2.47.3