summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/lib/libtime.tex7
-rw-r--r--Lib/_strptime.py44
-rw-r--r--Lib/test/test_strptime.py22
-rw-r--r--Misc/NEWS3
4 files changed, 72 insertions, 4 deletions
diff --git a/Doc/lib/libtime.tex b/Doc/lib/libtime.tex
index 5bca5bc..3b4ec7e 100644
--- a/Doc/lib/libtime.tex
+++ b/Doc/lib/libtime.tex
@@ -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
diff --git a/Lib/_strptime.py b/Lib/_strptime.py
index 17460ce..e2657d7 100644
--- a/Lib/_strptime.py
+++ b/Lib/_strptime.py
@@ -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
diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py
index 17f339b..bc68851 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
@@ -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."""
diff --git a/Misc/NEWS b/Misc/NEWS
index 7831f84..ebd0ba5 100644
--- 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
-----