Kaydet (Commit) 1fdb6335 authored tarafından Raymond Hettinger's avatar Raymond Hettinger

SF patch #691928: Use datetime in _strptime

Contributed by Brett Cannon.

To prevent code duplication, I patched _strptime to use datetime's date
object to do Julian day, Gregorian, and day of the week calculations.

Patch also includes new regression tests to test results and the
calculation gets triggered.

Very minor comment changes and the contact email are also changed.
üst c8df5780
......@@ -6,32 +6,25 @@ CLASSES:
time information as is returned by time.strftime()
FUNCTIONS:
firstjulian -- Calculates the Julian date up to the first of the specified
year
gregorian -- Calculates the Gregorian date based on the Julian day and
year
julianday -- Calculates the Julian day since the first of the year based
on the Gregorian date
dayofweek -- Calculates the day of the week from the Gregorian date.
_getlang -- Figure out what language is being used for the locale
strptime -- Calculates the time struct represented by the passed-in string
Requires Python 2.2.1 or higher.
Requires Python 2.2.1 or higher (mainly because of the use of property()).
Can be used in Python 2.2 if the following line is added:
>>> True = 1; False = 0
True = 1; False = 0
"""
import time
import locale
import calendar
from re import compile as re_compile
from re import IGNORECASE
from datetime import date as datetime_date
__author__ = "Brett Cannon"
__email__ = "drifty@bigfoot.com"
__email__ = "brett@python.org"
__all__ = ['strptime']
RegexpType = type(re_compile(''))
def _getlang():
# Figure out what the current language is set to.
current_lang = locale.getlocale(locale.LC_TIME)[0]
......@@ -425,7 +418,7 @@ def strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
month = day = 1
hour = minute = second = 0
tz = -1
# Defaulted to -1 so as to signal using functions to calc values
# 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():
......@@ -495,16 +488,21 @@ def strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
tz = 1
elif locale_time.timezone[2].lower() == found_zone:
tz = -1
#XXX <bc>: If calculating fxns are never exposed to the general
#populous then just inline calculations. Also might be able to use
#``datetime`` and the methods it provides.
# Cannot pre-calculate datetime_date() since can change in Julian
#calculation and thus could have different value for the day of the week
#calculation
if julian == -1:
julian = julianday(year, month, day)
else: # Assuming that if they bothered to include Julian day it will
# Need to add 1 to result since first day of the year is 1, not 0.
julian = datetime_date(year, month, day).toordinal() - \
datetime_date(year, 1, 1).toordinal() + 1
else: # Assume that if they bothered to include Julian day it will
#be accurate
year, month, day = gregorian(julian, year)
datetime_result = datetime_date.fromordinal((julian - 1) + datetime_date(year, 1, 1).toordinal())
year = datetime_result.year
month = datetime_result.month
day = datetime_result.day
if weekday == -1:
weekday = dayofweek(year, month, day)
weekday = datetime_date(year, month, day).weekday()
return time.struct_time((year, month, day,
hour, minute, second,
weekday, julian, tz))
......@@ -522,39 +520,3 @@ def _insensitiveindex(lst, findme):
else:
raise ValueError("value not in list")
def firstjulian(year):
"""Calculate the Julian date up until the first of the year."""
return ((146097 * (year + 4799)) // 400) - 31738
def julianday(year, month, day):
"""Calculate the Julian day since the beginning of the year.
Calculated from the Gregorian date.
"""
a = (14 - month) // 12
return (day - 32045
+ (((153 * (month + (12 * a) - 3)) + 2) // 5)
+ ((146097 * (year + 4800 - a)) // 400)) - firstjulian(year) + 1
def gregorian(julian, year):
"""Return 3-item list containing Gregorian date based on the Julian day."""
a = 32043 + julian + firstjulian(year)
b = ((4 * a) + 3) // 146097
c = a - ((146097 * b) // 4)
d = ((4 * c) + 3) // 1461
e = c - ((1461 * d) // 4)
m = ((5 * e) + 2) // 153
day = 1 + e - (((153 * m) + 2) // 5)
month = m + 3 - (12 * (m // 10))
year = (100 * b) + d - 4800 + (m // 10)
return [year, month, day]
def dayofweek(year, month, day):
"""Calculate the day of the week (Monday is 0)."""
a = (14 - month) // 12
y = year - a
weekday = (day + y + ((97 * y) // 400)
+ ((31 * (month + (12 * a) -2 )) // 12)) % 7
if weekday == 0:
return 6
else:
return weekday-1
......@@ -329,37 +329,6 @@ class StrptimeTests(unittest.TestCase):
"Default values for strptime() are incorrect;"
" %s != %s" % (strp_output, defaults))
class FxnTests(unittest.TestCase):
"""Test functions that fill in info by validating result and are triggered
properly."""
def setUp(self):
"""Create an initial time tuple."""
self.time_tuple = time.gmtime()
def test_julianday_result(self):
# Test julianday
result = _strptime.julianday(self.time_tuple[0], self.time_tuple[1],
self.time_tuple[2])
self.failUnless(result == self.time_tuple[7],
"julianday failed; %s != %s" %
(result, self.time_tuple[7]))
def test_gregorian_result(self):
# Test gregorian
result = _strptime.gregorian(self.time_tuple[7], self.time_tuple[0])
comparison = [self.time_tuple[0], self.time_tuple[1], self.time_tuple[2]]
self.failUnless(result == comparison,
"gregorian() failed; %s != %s" % (result, comparison))
def test_dayofweek_result(self):
# Test dayofweek
result = _strptime.dayofweek(self.time_tuple[0], self.time_tuple[1],
self.time_tuple[2])
comparison = self.time_tuple[6]
self.failUnless(result == comparison,
"dayofweek() failed; %s != %s" % (result, comparison))
class Strptime12AMPMTests(unittest.TestCase):
"""Test a _strptime regression in '%I %p' at 12 noon (12 PM)"""
......@@ -380,15 +349,52 @@ class JulianTests(unittest.TestCase):
# use 2004, since it is a leap year, we have 366 days
eq(_strptime.strptime('%d 2004' % i, '%j %Y')[7], i)
class CalculationTests(unittest.TestCase):
"""Test that strptime() fills in missing info correctly"""
def setUp(self):
self.time_tuple = time.gmtime()
def test_julian_calculation(self):
# Make sure that when Julian is missing that it is calculated
format_string = "%Y %m %d %H %M %S %w %Z"
result = _strptime.strptime(time.strftime(format_string, self.time_tuple),
format_string)
self.failUnless(result.tm_yday == self.time_tuple.tm_yday,
"Calculation of tm_yday failed; %s != %s" %
(result.tm_yday, self.time_tuple.tm_yday))
def test_gregorian_calculation(self):
# Test that Gregorian date can be calculated from Julian day
format_string = "%Y %H %M %S %w %j %Z"
result = _strptime.strptime(time.strftime(format_string, self.time_tuple),
format_string)
self.failUnless(result.tm_year == self.time_tuple.tm_year and
result.tm_mon == self.time_tuple.tm_mon and
result.tm_mday == self.time_tuple.tm_mday,
"Calculation of Gregorian date failed;"
"%s-%s-%s != %s-%s-%s" %
(result.tm_year, result.tm_mon, result.tm_mday,
self.time_tuple.tm_year, self.time_tuple.tm_mon,
self.time_tuple.tm_mday))
def test_day_of_week_calculation(self):
# Test that the day of the week is calculated as needed
format_string = "%Y %m %d %H %S %j %Z"
result = _strptime.strptime(time.strftime(format_string, self.time_tuple),
format_string)
self.failUnless(result.tm_wday == self.time_tuple.tm_wday,
"Calculation of day of the week failed;"
"%s != %s" % (result.tm_wday, self.time_tuple.tm_wday))
def test_main():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(LocaleTime_Tests))
suite.addTest(unittest.makeSuite(TimeRETests))
suite.addTest(unittest.makeSuite(StrptimeTests))
suite.addTest(unittest.makeSuite(FxnTests))
suite.addTest(unittest.makeSuite(Strptime12AMPMTests))
suite.addTest(unittest.makeSuite(JulianTests))
suite.addTest(unittest.makeSuite(CalculationTests))
test_support.run_suite(suite)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment