mirror of https://github.com/python/cpython
Add support for %U and %W to contribute to calculating the date when the year
and day of the week are specified. Closes bug #1045381.
This commit is contained in:
parent
be8370dc9c
commit
8abcc5d533
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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."""
|
||||
|
|
Loading…
Reference in New Issue