]> granicus.if.org Git - python/commitdiff
Add support for %U and %W to contribute to calculating the date when the year
authorBrett Cannon <bcannon@gmail.com>
Mon, 18 Oct 2004 01:37:57 +0000 (01:37 +0000)
committerBrett Cannon <bcannon@gmail.com>
Mon, 18 Oct 2004 01:37:57 +0000 (01:37 +0000)
and day of the week are specified.

Closes bug #1045381.

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

index 5bca5bc88ad15ba8af3064436779678866f60206..3b4ec7e83b6da2c401436ccbacce3c9c4cbc48b3 100644 (file)
@@ -247,11 +247,11 @@ specification, and are replaced by the indicated characters in the
   \lineiii{\%S}{Second as a decimal number [00,61].}{(2)}
   \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.}{(3)}
   \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.}{(3)}
   \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].}{}
@@ -271,6 +271,9 @@ Notes:
   \item[(2)]
     The range really is \code{0} to \code{61}; this accounts for leap
     seconds and the (very rare) double leap seconds.
+  \item[(3)]
+    \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 17460ce98090723eebfd8607f7b818ecba856b95..e2657d728bae84e3176224736caac0c1fdd563ff 100644 (file)
@@ -212,7 +212,7 @@ class TimeRE(dict):
                                         for tz in tz_names),
                                 'Z'),
             '%': '%'})
-        base.__setitem__('W', base.__getitem__('U'))
+        base.__setitem__('W', base.__getitem__('U').replace('U', 'W'))
         base.__setitem__('c', self.pattern(self.locale_time.LC_date_time))
         base.__setitem__('x', self.pattern(self.locale_time.LC_date))
         base.__setitem__('X', self.pattern(self.locale_time.LC_time))
@@ -298,10 +298,17 @@ 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()
     for group_key in found_dict.iterkeys():
+        # Directives not explicitly handled below:
+        #   c, x, X
+        #      handled by making out of other directives
+        #   U, W
+        #      worthless without day of the week
         if group_key == 'y':
             year = int(found_dict['y'])
             # Open Group specification for strptime() states that a %y
@@ -355,6 +362,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.
@@ -370,6 +385,33 @@ def strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
                     else:
                         tz = value
                         break
+    # 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
+    # XXX only works for W
+    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 17f339b349eadf78e8ce8e83cbe7e97a29d0339d..bc68851023e49592a08dece8e1e51eed92cdcf94 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
 
@@ -417,6 +418,27 @@ 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 7831f847a69fc59bae9e83ab047052e5b036a586..ebd0ba513e32344d10aa41526b924ea97d821f56 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -22,7 +22,8 @@ Extension Modules
 Library
 -------
 
-...
+- Bug #1045381: time.strptime() can now infer the date using %U or %W (week of
+  the year) when the day of the week and year are also specified.
 
 Build
 -----