]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Add support for using %U and %W in strptime when year and day of the week are
authorBrett Cannon <bcannon@gmail.com>
Mon, 18 Oct 2004 01:56:17 +0000 (01:56 +0000)
committerBrett Cannon <bcannon@gmail.com>
Mon, 18 Oct 2004 01:56:17 +0000 (01:56 +0000)
also specified.

Closes bug #1045381.

Doc/lib/libtime.tex
Lib/_strptime.py
Lib/test/test_strptime.py
Misc/NEWS

index 0929c179d5df687d9ee551183974f077e3297299..5d8fe639e3bb9a6bc4d3fea64dfa734850219ff8 100644 (file)
@@ -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 
index cc578305ad98ddde590a21cfa8b08c5c23373259..d3959ae754ddef5757705882d37310e4b61a09c1 100644 (file)
@@ -311,7 +311,7 @@ class TimeRE(dict):
             # W is set below by using 'U'
             'y': r"(?P<y>\d\d)",
             'Y': r"(?P<Y>\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
index 869954c1ec5875f0f21f50b6a68e0afe1b4a9f57..09b59212d6b3521314e6552d802ec0948f3f9691 100644 (file)
@@ -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."""
 
index 15b6b7f7b129ad455e46c8e79e0335bccdcc6963..f598834bf13b95d34e0f2438cacd77b372272657 100644 (file)
--- 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.