-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
WIP: bpo-1100942: Add datetime.time.strptime and datetime.date.strptime #5578
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ad5ffab
50606eb
ab5030f
07fb326
010ac8b
5b58fc1
8353a65
cff74a9
f92a799
4c4a7cc
b006172
ff7487f
a048f0e
9ac0af4
a952bb7
412aea2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -175,6 +175,15 @@ Added :func:`~gettext.pgettext` and its variants. | |
(Contributed by Franz Glasner, Éric Araujo, and Cheryl Sabella in :issue:`2504`.) | ||
|
||
|
||
datetime | ||
-------- | ||
|
||
Added :func:`~datetime.date.strptime` and :func:`~datetime.time.strptime`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I expect you lose the reference to date and time, so all you are saying is you added two functions with the same name repeated. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @vadmium yep, here, we just add the class methods |
||
(Patch by Alexander Belopolsky, Amaury Forgeot d'Arc, Berker Peksag, Josh-sf, | ||
Juraez Bochi, Maciej Szulik, Matheus Vieira Portela. Contributed by Stéphane | ||
Wirtel) | ||
|
||
|
||
gc | ||
-- | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
from re import IGNORECASE | ||
from re import escape as re_escape | ||
from datetime import (date as datetime_date, | ||
datetime as datetime_datetime, | ||
timedelta as datetime_timedelta, | ||
timezone as datetime_timezone) | ||
from _thread import allocate_lock as _thread_allocate_lock | ||
|
@@ -307,9 +308,9 @@ def _calc_julian_from_V(iso_year, iso_week, iso_weekday): | |
|
||
|
||
def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): | ||
"""Return a 2-tuple consisting of a time struct and an int containing | ||
"""Return a 3-tuple consisting of a time struct and an int containing | ||
the number of microseconds based on the input string and the | ||
format string.""" | ||
format string, and the UTC offset.""" | ||
|
||
for index, arg in enumerate([data_string, format]): | ||
if not isinstance(arg, str): | ||
|
@@ -556,6 +557,10 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): | |
hour, minute, second, | ||
weekday, julian, tz, tzname, gmtoff), fraction, gmtoff_fraction | ||
|
||
date_specs = ('%a', '%A', '%b', '%B', '%c', '%d', '%j', '%m', '%U', '%G', | ||
'%u', '%V', '%w', '%W', '%x', '%y', '%Y', '%G', '%u', '%V',) | ||
time_specs = ('%H', '%I', '%M', '%S', '%f',) | ||
|
||
def _strptime_time(data_string, format="%a %b %d %H:%M:%S %Y"): | ||
"""Return a time struct based on the input string and the | ||
format string.""" | ||
|
@@ -577,3 +582,19 @@ def _strptime_datetime(cls, data_string, format="%a %b %d %H:%M:%S %Y"): | |
args += (tz,) | ||
|
||
return cls(*args) | ||
|
||
def _strptime_datetime_date(data_string, format): | ||
"""Return a date based on the input string and the format string.""" | ||
msg = "'{!s}' {} not valid in date format specification." | ||
from _datetime import _check_invalid_datetime_specs | ||
if _check_invalid_datetime_specs(format, time_specs, msg): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not move the msg string into the check function, and just pass the bit that varies ('date' or 'time') as an argument? It would make the code easier to read. Looks like the check function either raises an exception or returns True. It would be clearer to not use an if statement here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. at the beginning, this PR was a submitted patch by other contributors, I just wanted to convert it to a PR. and now, I try to fix all the issues. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
_date = _strptime_datetime(datetime_datetime, data_string, format) | ||
return _date.date() | ||
|
||
def _strptime_datetime_time(data_string, format): | ||
"""Return a time based on the input string and the format string.""" | ||
msg = "'{!s}' {} not valid in time format specification." | ||
from _datetime import _check_invalid_datetime_specs | ||
if _check_invalid_datetime_specs(format, date_specs, msg): | ||
_time = _strptime_datetime(datetime_datetime, data_string, format) | ||
return _time.time() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1017,6 +1017,30 @@ def test_delta_non_days_ignored(self): | |
dt2 = dt - delta | ||
self.assertEqual(dt2, dt - days) | ||
|
||
def test_strptime_valid_format(self): | ||
tests = [ | ||
('2004-12-01', '%Y-%m-%d', date(2004, 12, 1)), | ||
('2004', '%Y', date(2004, 1, 1)), | ||
] | ||
for date_string, date_format, expected in tests: | ||
with self.subTest(date_string=date_string, | ||
date_format=date_format, | ||
expected=expected): | ||
self.assertEqual(expected, date.strptime(date_string, date_format)) | ||
|
||
def test_strptime_invalid_format(self): | ||
tests = [ | ||
('2004-12-01 13:02:47.197', '%Y-%m-%d %H:%M:%S.%f'), | ||
('2018-01-01', ''), | ||
('01', '%M'), | ||
('02', '%H'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs at least two more test cases: ('2018-01-01 00:00', '%Y-%m-%d %H:%M'),
('2018-01-01', ''), Both should fail. |
||
] | ||
for hour, format in tests: | ||
with self.subTest(hour=hour, format=format): | ||
with self.assertRaises(ValueError): | ||
date.strptime(hour, format) | ||
|
||
|
||
class SubclassDate(date): | ||
sub_var = 1 | ||
|
||
|
@@ -3105,6 +3129,25 @@ def test_strftime(self): | |
except UnicodeEncodeError: | ||
pass | ||
|
||
def test_strptime_invalid(self): | ||
tests = [ | ||
('2004-12-01 13:02:47.197', '%Y-%m-%d %H:%M:%S.%f'), | ||
('2004-12-01', '%Y-%m-%d'), | ||
('12:30:15', ''), | ||
] | ||
for date_string, date_format in tests: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be good to use Also, per the other comment I guess you need to add something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you need two more test cases: ('1900-01-01 12:30', '%Y-%m-%d %H:%M'),
('12:30:15', ''),
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the test with For the other test, yep, there is an issue. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The fact that it doesn't raise an exception is an issue. I'm a bit surprised that it doesn't raise an exception on pure Python, that's a bug, because I'm pretty sure that:
|
||
with self.subTest(date_string=date_string, date_format=date_format): | ||
with self.assertRaises(ValueError): | ||
time.strptime(date_string, date_format) | ||
|
||
def test_strptime_valid(self): | ||
string = '13:02:47.197' | ||
format = '%H:%M:%S.%f' | ||
result, frac, gmtoff = _strptime._strptime(string, format) | ||
expected = self.theclass(*(result[3:6] + (frac, ))) | ||
got = time.strptime(string, format) | ||
self.assertEqual(expected, got) | ||
|
||
def test_format(self): | ||
t = self.theclass(1, 2, 3, 4) | ||
self.assertEqual(t.__format__(''), str(t)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add :func:`datetime.date.strptime` and :func:`datetime.time.strptime` class methods. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add something like "For a complete list of formatting directives, see strftime() and strptime() Behavior." with a link? (copy the sentence from datetime.datetime.strptime) Just from this doc, I have no idea of what is the expected format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done