Repository navigation
datetime: add ability to parse RFC 3339 dates and times #60077
Copy link
Copy link
Closed
Labels
3.7 (EOL)end of lifeend of lifestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancement
Description
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = 'https://github.com/abalkin'
closed_at = <Date 2018-03-01.18:50:17.237>
created_at = <Date 2012-09-06.21:08:49.605>
labels = ['3.7', 'type-feature', 'library']
title = 'datetime: add ability to parse RFC 3339 dates and times'
updated_at = <Date 2018-03-01.18:50:17.236>
user = 'https://bugs.python.org/nagle'bugs.python.org fields:
activity = <Date 2018-03-01.18:50:17.236>
actor = 'belopolsky'
assignee = 'belopolsky'
closed = True
closed_date = <Date 2018-03-01.18:50:17.237>
closer = 'belopolsky'
components = ['Library (Lib)']
creation = <Date 2012-09-06.21:08:49.605>
creator = 'nagle'
dependencies = []
files = ['27141', '27165', '41922', '41923', '41926', '41927', '41934', '41935', '41940', '41945', '41951', '44015', '44016', '44019']
hgrepos = []
issue_num = 15873
keywords = ['patch']
message_count = 90.0
messages = ['169941', '169952', '169966', '169968', '169970', '170098', '170104', '170109', '170112', '170114', '170116', '170180', '170181', '174339', '183672', '183743', '183809', '183921', '183931', '221829', '221830', '221831', '221903', '260099', '260100', '260150', '260266', '260276', '260280', '260282', '260292', '260293', '260294', '260295', '260298', '260303', '260309', '260318', '260337', '260342', '260343', '260344', '260345', '260347', '260350', '260356', '260382', '260420', '260426', '260427', '260440', '260441', '260442', '260445', '260449', '260989', '260990', '260991', '263867', '269714', '269722', '270529', '270828', '270829', '270831', '270899', '272021', '272026', '273609', '291822', '291831', '304950', '307603', '307604', '307605', '307606', '307607', '307610', '307616', '308214', '308505', '308507', '308510', '308569', '308637', '308851', '309168', '309175', '311703', '313105']
nosy_count = 36.0
nosy_names = ['barry', 'jcea', 'cben', 'roysmith', 'ncoghlan', 'belopolsky', 'nagle', 'vstinner', 'jwilk', 'mcepl', 'eric.araujo', 'Arfrever', 'r.david.murray', 'davydov', 'cvrebert', 'karlcow', 'SilentGhost', 'Elvis.Pranskevichus', 'perey', 'flying sheep', 'mihaic', 'aymeric.augustin', 'Roman.Evstifeev', 'berker.peksag', 'martin.panter', 'piotr.dobrogost', 'kirpit', 'Anders.Hovm\xc3\xb6ller', 'jstasiak', 'Eric.Hanchrow', 'deronnax', 'pbryan', 'p-ganssle', 'sirex', 'larsonreever', 'jaitaiwan']
pr_nums = ['4699', '4841', '5559', '5559', '5939']
priority = 'normal'
resolution = 'fixed'
stage = 'resolved'
status = 'closed'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue15873'
versions = ['Python 3.7']Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
3.7 (EOL)end of lifeend of lifestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancement
Activity
roysmith commentedon Sep 10, 2012
Ooops, clicked the wrong button.
flying-sheep commentedon Oct 31, 2012
there is a module that parses those strings pretty nicely, it’s called pyiso8601: http://code.google.com/p/pyiso8601/
in the context of writing a better plistlib, i also needed the capability to parse those strings, and decided not to use the sucky incomplete implementation of plistlib, but the one mentioned above.
i py3ified it, eliminating quite some code, and the result is pretty terse, check it out: https://github.com/flying-sheep/plist/blob/master/iso8601.py
note that that implementation returns utc-datetimes for timezoneless strings, instead of naive ones. (l.30)
boxed commentedon Mar 7, 2013
I've written a parser for ISO 8601: https://github.com/boxed/iso8601
Some basic tests are included and it supports most of the standard. Haven't gotten around to the more obscure parts like durations and intervals, but those are trivial to add...
merwok commentedon Mar 8, 2013
Are you offering the module for inclusion in the stdlib?
boxed commentedon Mar 9, 2013
Éric Araujo: absolutely. Although I think my code can be improved (speed wise, elegance, etc) since I just wrote it quickly a weekend :)
merwok commentedon Mar 11, 2013
John listed four modules with issues in the first message, and now we have proposals for two more modules. Could you work together to make a unified patch?
Alexander, do you think there is a need to check python-ideas or python-dev before working on this?
(I changed the title to clarify scope: ISO 8601 is huge and not easily accessible whereas W3CDTF/RFC 3339 is narrower in scope and freely accessible.)
[-]"datetime" cannot parse ISO 8601 dates and times[/-][+]datetime: add ability to parse RFC 3339 dates and times[/+]abalkin commentedon Mar 11, 2013
Éric> do you think there is a need to check python-ideas or python-dev before working on this?
Yes, I think this is python-ideas material. IMHO, what should be added to datetime module in 3.4 is ability to construct date/time objects from their str() representation:
assert time(str(t)) == t
assert date(str(d)) == d
assert datetime(str(dt)) == dt
I am not sure the same is needed for timedelta, but this can be discussed.
Implementation of any external to python standard should be wetted at PyPI first. There may be a reason why there is no rfc3339.py module on PyPI.
karlcow commentedon Jun 29, 2014
I had the issue today. I needed to parse a date with the following format.
and could not with strptime.
I see a discussion in March 2014 http://code.activestate.com/lists/python-ideas/26883/ but no followup.
For references:
http://www.w3.org/TR/NOTE-datetime
http://tools.ietf.org/html/rfc3339
karlcow commentedon Jun 29, 2014
On closer inspection, Anders Hovmöller proposal doesn't work.
https://github.com/boxed/iso8601
At least for the microseconds part.
In http://tools.ietf.org/html/rfc3339#section-5.6, the microsecond part is defined as:
time-secfrac = "." 1*DIGIT
In http://www.w3.org/TR/NOTE-datetime, same thing:
s = one or more digits representing a decimal fraction of a second
Anders considers it to be only six digits. It can be more or it can be less. :)
Will comment on github too.
karlcow commentedon Jun 29, 2014
Noticed some people doing the same thing
https://github.com/tonyg/python-rfc3339
http://home.blarg.net/~steveha/pyfeed.html
https://wiki.python.org/moin/WorkingWithTime
karlcow commentedon Jun 29, 2014
After inspections, the best library for parsing RFC3339 style date is definitely:
https://github.com/tonyg/python-rfc3339/
Main code at
https://github.com/tonyg/python-rfc3339/blob/master/rfc3339.py
deronnax commentedon Feb 11, 2016
So, shall we include it ? Otherwise, py8601 (https://bitbucket.org/micktwomey/pyiso8601/) looks pretty popular and well maintained (various committers, started in 2012, last commit in 2016).
I think we should hurry, that's a great shame it has been while Python is able to generate a 8601 datetime but not parsing it back.
vstinner commentedon Feb 11, 2016
I'm working on the OpenStack project and iso8601 is heavily used.
I don't think that we should add the iso8601 module to the stdlib, but merge iso8601 "features" into the datetime module.
The iso8601 module supports Python 2.7 and so has to implement its own timezone classes. The datetime module now has datetime.timezone since Python 3.2 for fixed timezone.
The iso8601 module provides functions. I would prefer datetime.datetime *methods*.
Would you mind to try to implement that? It would be kind to contact iso8601 author before.
The important part is also unit tests.
vstinner commentedon Feb 12, 2016
See also bpo-12006 for ISO 8601: "The datetime.strftime() and date.strftime() methods now support ISO 8601 date directives %G, %u and %V. (Contributed by Ashley Anderson in bpo-12006.)".
deronnax commentedon Feb 14, 2016
bpo-12006 will unfortunately of no use for this one.
Actually, I realized that the best implementation of parsing rfc 3339 is in django dateparse utils. To me it's the finest, the most elegant, and no other one can claim to be more robust since it's probably the #1 iso parsing functions used in python. Have a look at https://docs.djangoproject.com/en/1.9/_modules/django/utils/dateparse/#parse_datetime
Alexander, I won't start before I have your opinion. What do you think ?
deronnax commentedon Feb 14, 2016
Here is the PoC with code taken from django.utils.parse_datetime and adapted for the datetime module (I didn't ask for their agreement yet). Of course tests pass. For me it's the most elegant solution.
(I think date and time also need their "fromisotimestamp" counterpart).
deronnax commentedon Feb 14, 2016
(slightly improved version, better use of timedelta)
vstinner commentedon Feb 14, 2016
Is the django license compatible with the Python license?
deronnax commentedon Feb 15, 2016
I don't know. The taken code is really little, modified, and is nothing much that an implementation you had seen a while ago, and recoded by memory not remembering where you saw it in the first place. Do you think that's really an issue ?
karlcow commentedon Feb 15, 2016
From https://www.djangoproject.com/foundation/cla/faq/
karlcow commentedon Feb 15, 2016
About
How does it parse this date:
2016-02-15T11:59:46.16588638674+09:00
deronnax commentedon Feb 15, 2016
discarding the microseconds digits after the 6th.
2016-02-15 13:30 GMT+10:30 karl <report@bugs.python.org>:
deronnax commentedon Feb 15, 2016
slightly improved + addresses issues stated here : https://bugs.python.org/review/15873/diff/16581/Lib/datetime.py#newcode1418Lib/datetime.py:1418
vstinner commentedon Feb 15, 2016
Mathieu Dupuy added the comment:
Hum, you should use the same rounding method than
datetime.datetime.fromtimestamp(): ROUND_HALF_UP, as round().
In practice, you can for example pass a floating point number as
microseconds to datetime.datetime constructor.
Since datetime is implemented in C, I'm not sure that using the re is
the best choice. Since the regex looks simple enough, we may parse the
string without the re module. Well, maybe only for the C
implementation.
What is the behaviour is there are spaces before/after the string?
What if there are other characters like letters before/after? You
should add an unit test for that. I expect an error when parsing
"t=2012-04-23T09:15:00" for example.
Your regex ends with $ but doesn't start with ^. Using re.match(), ^
and $ are probably not needed, but I'm not confident when I use regex
:-)
deronnax commentedon Feb 15, 2016
Unfortunately, you're mistaking with the timedelta constructor. Datetime's one only take int :(
But I figured out an elegant manner to cope with (in my opinion)
No regex available at all in CPython ? Otherwise, yeah, if I have to, I can do it with strptime.
re.match only look at the beginning of the string, so no need for '^'. And therefore, the case
you mention is already handled :)
joined to this mail the last revision of the feature, with correct rounding, more test and one useless
line removed. Maybe the good one :) ?
vstinner commentedon Feb 15, 2016
It's not really convenient to use the re module in C.
I suggest to parse directly the string with C code, since the format looks quite simple (numbers and a few separators).
deronnax commentedon Feb 15, 2016
But some of them are optional. And I would really like to mimic the same implementation logic in C.
Now I think the python version is fairly ready. What next ?
vadmium commentedon Feb 16, 2016
It looks to me like you copied a lot of code, doc strings, tests, etc from <django/django@9b1cb75#diff-4db1d116f25f482278090b122e3b0028%5C%3E and <django/django@2f59e94\>. I wouldn’t call it trivial. There is a BSD license for Django. Or do we have to get the relevant authors to do the Python CLA thing?
The current patch seems to allow a timezone without a colon, or even without minutes (+1100 and +11 as well as the RFC’s +11:00). Is this needed? The colon was made optional in Django in <https://code.djangoproject.com/ticket/18728\>; the argument given for this just seems to be ISO 8601 alignment, nothing practical. According to <https://code.djangoproject.com/ticket/22814\> Postgre SQL outputs time zones without the minutes field, but I don’t know if Python should go out of its way to support this obscure format.
RFC 3339 does not specify single digits in many places (e.g. 2016-2-1 1:0:0 is not specified). Should we also be stricter, at least for the minutes and seconds fields?
Also, is it necessary to allow the seconds field to be omitted, as in "2016-02-01 01:21"?
It seems that the “datetime” module does not support leap seconds, so if we mention RFC 3339 we should point out this inconsistency.
Victor: From my limited experiments, datetime.fromtimestamp() seems to use the round-to-even rule (not always rounding half up). Can you confirm? Maybe we should use that for consistency if it is practical. Otherwise, truncation towards zero would be the simplest.
As well as adding datetime.fromisoformat(), I think we should add similar methods to the separate date and time classes. One can parse the RFC’s full-date format fairly easily with strptime(), but not so for partial-time because of the fractional seconds.
deronnax commentedon Feb 16, 2016
The real question is : should we accept whatever iso8601 format is common to be found on the internet, or just be able to consume back the string issued by isoformat. From that results the answers to the questions you're asking: don't accept single digits, neither second-less datetime, ...
I don't really mind what the answer is. I'm OK for a stricter acceptance. I would like to ask ourselves : does a simpler, stricter implementation fulfill people needs ? If it's OK for you, it's OK for me.
By taking the Django version, I deviated the bit from the author's original need which was just being able to parse back datetime isoformat. The limitations he raises for not using strptime are gone now (strptime understand timezone), but it still can't understand microseconds nor optional parts (T or space for separator, optional microseconds). Even for a much simpler, stricter implementation, I'd like to stick with regex.
I'll do a date & time version, I just wait that we fall agree on the whole datetime thing.
Wether we change to a simpler code or keep it this way, I can rewrite tests & docstring.
vadmium commentedon Feb 16, 2016
The regular expression r"\d" matches any digit in Unicode I think, not just ASCII digits 0-9. Perhaps we should limit it to ASCII digits. Or is it intended to allow non-ASCII digits like in "२०१६-०२-१६ ०१:२१:१४"?
deronnax commentedon Feb 16, 2016
Oh my god you're right. Thanks there is the re.ASCII flag.
2016-02-16 15:07 GMT+10:30 Martin Panter <report@bugs.python.org>:
deronnax commentedon Feb 16, 2016
simpler version using a simpler, stricter regex
deronnax commentedon Feb 16, 2016
(OK, I said a stupidity: datetime's strptime handle microseconds. But time's one doesn't)
deronnax commentedon Feb 16, 2016
OK, I know I post a lot, but this one should be the good one:
I'm impatient to receive your feedback.
deronnax commentedon Feb 17, 2016
Crap, I just checked spams today and almost all mails of the reviewboard landed in spams ! So I made a new patch addressing all concerns:
bonus:
I still have a doubt though about the place I moved the regex. Tell me.
vadmium commentedon Feb 18, 2016
Hi Aymeric Augustin. I am guessing you are the original author of the code and tests in Django for parsing datetime strings (https://bugs.python.org/issue15873#msg260342). If so, would you be happy for it to be incorporated into Python?
Mathieu: I left a couple quick review comments. (Normally I leave a message in the main bug thread, but I forgot the other time.)
Doc strings: Generally I think we keep the doc strings to a minimum, and leave the main documentation for the RST files. For the RST documentation, I would suggest including a rough summary of the format. E.g. for time.fromisoformat(), something like “The string should be in the RFC’s ‘full-time’ format, which looks like HH:MM:SS[.mmmmmm][Z|±HH:MM].”
Now that you added the two new regex strings, I can see that it might be useful to keep them together, rather than next to each class. Or you could even make them class attributes. No strong opinions either way; whatever works for you I think.
deronnax commentedon Feb 18, 2016
New patch with all your concerns addressed (martin.panther+ silentghost) EXCEPT the single dispatch dictionary thing.
deronnax commentedon Feb 18, 2016
SilentGhost: the dictionary single dispatch thing attached (apply on top of the last, fromisoformat_new3).
I mind the performance penalty for date-only parsing users, but the code is definitively shorter and more elegant.
But we have a major problem: tests fails because what is used in tests is a subclass of datetime classes (Subclass[Date|Time|DateTime]) and thus, the dispatch break with a KeyError: class.SubDate[...]. I have no idea on how mitigate that. Do you ?
aymericaugustin commentedon Feb 18, 2016
martin.panter: of course, I'm fine with integrating that code into Python.
deronnax: could you create a ticket on https://code.djangoproject.com/ highlighting the differences between Django's original implementation and the improved version that you worked on?
I'd like to use the stdlib implementation when it's available and align Django's current implementation to whatever's getting into the stdlib (to prepare the transition, even though we aren't going to drop support for Python 3.5 soon).
SilentGhost commentedon Feb 18, 2016
Mathieu, nothing was attached. The penalty's worth only a few if statements, I wouldn't worry too much about it. Besides, a C version is going to be provided as well, right?
Perhaps the following approach might solve the subclasses problem:
Perhaps, TypeError is unnecessary there and just propagating StopIteration would do. In that case the if clause would look like:
deronnax commentedon Feb 18, 2016
crap, here is the attachment.
Yeah, but I really would like to use regex in the C version (unless you strongly disadvise), so we will have the same logic and the same problem. And I never made a patch for the C interpreter itself, so the C equivalent is not close to be here soon. (btw if you have a starting point to recommend)
I definitely do not like this fix, it destroys the elegance and the simplicity of the "single-dispatch" solution. And it introduce a lot of noisy code for a very rare case, people subclassing datetime.* classes.
Maybe making the regex dictionary having string keys instead of class and passing the correct string from the calling function, like:
or maybe functools.singledispatch handle this case ?
SilentGhost commentedon Feb 18, 2016
Probably only other solution that I see is to add the third argument, an actual class, e.g.:
vadmium commentedon Feb 18, 2016
Did you see my class attributes suggestion a couple messages back? That might solve your dispatch problem:
# or
For the C module, start looking at /Modules/datetimemodule.c. Maybe if you can think of a similar function implemented in C to copy off. It looks like strptime() defers to a Python-only implementation; maybe that is another option.
deronnax commentedon Feb 29, 2016
What I really want is to use regex in the C part as I did for the python one. It's the best approach and by very far.
I need to figure out how to use regex in CPython internals.
If I defer the actual processing to the Python part, what's the point of doing a C part ?
vstinner commentedon Feb 29, 2016
Currently, the "datetime" module is fully implemented in C, it's the
_datetime module in practice (accessed by the datetime module
namespace).
deronnax commentedon Feb 29, 2016
I know. Martin was suggesting to defer the processing to an actual Python implementation, hence my answer.
vadmium commentedon Apr 21, 2016
If you decide to only do a Python implementation, the main reason to write a wrapper in C would be because the datetime class is defined in C. Similar to how the datetime_strptime() function in Modules/_datetimemodule.c imports and calls _strptime._strptime_datetime().
An alternative might be to subclass the C classes _datetime.datetime, etc, and define the methods directly in those subclasses. Similar to how the C-defined class _socket.socket is subclassed in Lib/socket.py and more methods are added.
deronnax commentedon Jul 2, 2016
Hi.
I'm back, and willing to move forward on this issue. With the new code layout, the compiled regexes now lay in datetime classes as class attributes. Will it be possible to import date, time and datetime from datetime.py in _datetime.c without a problem ?
By the way, I just discovered, that the way we treat microseconds differs from the strptime one : we are smarter read every digits and smartly round to six, strptime doesn't go that far and just *truncate* to this. Should go that way, for consistency with what strptime does, maybe ?
boxed commentedon Jul 2, 2016
I'm strongly against silently throwing away data and calling it even. If we want compatibility with strptime then it should be a separate flag like silent_truncate_milliseconds=True.
On another matter: does the latest proposed code pass the tests in my ISO8601 implementation that I mentioned 2013 (! time flies)?
abalkin commentedon Jul 16, 2016
I would very much like to see this ready before the feature cut-off for Python 3.6. Could someone post a summary on python-ideas to get a show of hands on some of the remaining wrinkles?
I would not worry about a C implementation at this point. We can put python implementation in _strptime.py and call it from C as we do for the strptime method.
boxed commentedon Jul 19, 2016
The tests attached to this ticket seem pretty bare. Issues that I can spot directly:
(the above list is a copy paste from my project that implements all ISO8601 that fits into native python: https://github.com/boxed/iso8601 <https://github.com/boxed/iso8601\>)
This is a more reasonable test suite: https://github.com/boxed/iso8601/blob/master/iso8601.py#L166 <https://github.com/boxed/iso8601/blob/master/iso8601.py#L166\> although it lacks the tests for bogus inputs.
deronnax commentedon Jul 19, 2016
because it limits itself to only support the RFC 3339 subset, as
explained in the begining of the discussion.
2016-07-19 16:07 GMT+02:00 Anders Hovmöller <report@bugs.python.org>:
boxed commentedon Jul 19, 2016
Hmm, ok. I guess I was confused by "dates and times" part of the subject. Ok, so only datetimes. My other comments still apply though.
vadmium commentedon Jul 21, 2016
Mathieu: Maybe you haven’t seen some of the comments on your older patches. E.g. my comment on fromisoformat4.patch about improper use of “with self.assertRaises(...)” still stands.
Also, adding some documentation to the patch might help the likes of Anders figure out the scope of the change. I think we decided to parse RFC 3339’s “internet date and time format” profile of ISO 8601 with the date, time, and datetime classes, including tolerating arbitrary resolutions of fractions of seconds in the time, and parsing time zones.
I don’t think we need to test every combination of the other ISO 8601 formats. There are already a couple of negative tests. Are there any in particular you think are important to add?
deronnax commentedon Aug 5, 2016
I'm back on the issue. I'm currently stuck on the design. We need to store the regexes somewhere, and that's what causes problem : I can't really find a good place to store them. We basically have two possible designs :
single dispatch kind, class-type dictionary lookup for regexes, stored in _strpime.py. It's minimally invasive, allow a very simple C implementation, and allows us to avoid to add a 're' import in datetime.py. Problem : it breaks when the given class is not of type date, time or datetime. And it currently breaks the tests because tests are doing this, testing using subclasses. We could rely on "isinstance" but do we want this ?
regex stored as classes attributes. More robust, more invasive, 're' import in datetime.py, allows subclassing, passes test. C implementation not done yet. Since it requires a better understanding of the C API, I will do it only we are sure that's the way to go.
I post the two versions of the implementation as patches here. These adress all the concerns expressed before (Martin). If we can't decide, I will post a mail on the mailing list Martin suggested, python-ideas. By the way, are you sure it's the right one to ask ? Wouldn't be python-dev more appropriated ?
deronnax commentedon Aug 5, 2016
updated version with SilentGhost's concerns addressed.
abalkin commentedon Aug 24, 2016
Please move _parse_isotime to _strptime so that it can be called from C implementation. Also, the new method should be documented.
larsonreever commentedon Apr 18, 2017
Otherwise, py8601 (https://bitbucket.org/micktwomey/pyiso8601/) looks pretty popular and well maintained (various committers, started in 2012, last commit in 2016). I don't think that we should add the iso8601 module to the stdlib, but merge iso8601 "features" into the datetime module. The iso8601 module supports Python 2.7 and so has to implement its own timezone classes. The datetime module now has datetime.timezone since Python 3.2 for fixed timezone. To me it's the finest, the most elegant, and no other one can claim to be more robust since it's probably the #1 iso parsing functions used in python. Have a look at https://docs.djangoproject.com/en/1.9/_modules/django/utils/dateparse/#parse_datetime.
boxed commentedon Apr 18, 2017
@larsonreever That lib is pretty limited, in that it doesn't handle dates or deltas. Again: my lib that is linked above does and has comprehensive tests.
elprans commentedon Oct 24, 2017
I think that both the pyiso8601 and boxed/iso8601 implementations parse ISO 8601 strings incorrectly. The standard explicitly says that all truncated datetime strings are *reduced accuracy timestamps*. In other words, "2017-10" is *not* equal to "2017-10-01". Instead, "2017-10" represents the whole month of October 2017. Same thing with hours. Earlier versions of ISO 8601 even allowed dropping the year: "--10-01", which meant October 1st of _any year_. They dropped this from more recent revisions of the standard.
The only place where the truncated representation means "default to zero" is the timezone offset, so "10:10:00+4" and "10:10:00+04:00" mean the same thing.
vadmium commentedon Dec 4, 2017
P-ganssle seems to be proposing to limit parsing to exactly what “datetime.isoformat” produces; i.e. whole number of seconds, milliseconds or microseconds. Personally I would prefer it without this limitation, like in Mathieu’s patches. But P-ganssle has done some documentation, so perhaps we can combine the work of each?
vadmium commentedon Dec 4, 2017
The other difference is Mattieu guarantees ValueError for invalid input strings, which I think is good.
abalkin commentedon Dec 4, 2017
The better is the enemy of the good here. Given the history of this issue, I would rather accept a well documented restrictive parser than wait for a more general code to be written. Note that we can always relax the parsing rules in the future.
deronnax commentedon Dec 4, 2017
I'm right now available again to work on this issue. I'll submit a pull
request within a week with all issues addressed
Le 4 déc. 2017 11:45 PM, "Alexander Belopolsky" <report@bugs.python.org> a
écrit :
pganssle commentedon Dec 5, 2017
This is in fact the exact reason why I wrote the isoformat parser like I did, because ISO 8601 is actually a quite expansive standard, and this is the least controversial subset of the features. In fact, I spent quite a bit of time on adapting the general purpose ISO8601 parser I wrote for dateutil *into* one that only accepts the output of isoformat() because it places a minimum burden on ongoing support, so it's not really a matter of waiting for a more general parser to be written.
I suggest that for Python 3.7 we only support output of isoformat(). Many general iso8601 parsers exist, including the one I have already implemented for python-dateutil (which will be part of the dateutil 2.7.0 release). We can have further discussion later about what exactly should be supported in Python 3.8, but even in the pre-release discussions I'm already seeing pushback about some of the more unusual 8601 formats, and it's a lot easier to explain (in documentation) that
fromisoformat()is intended to be the inverse ofisoformat()than it is to explain which variations of ISO 8601 are and are not supported (fractional minutes? if you're following the standard, the separator has to be a T, so what other variations of the standard are allowed?).abalkin commentedon Dec 5, 2017
+1 on what Paul said.
Mathieu, the goal for 3.7 will be to get Paul's PR merged. It will be great if you could help in reviewing it. We can return to the features in your PR during the 3.8 development cycle.
pganssle commentedon Dec 5, 2017
I forgot to address this - but I don't think this is a difference in approaches. If you pass
Noneor an int or something, the problem is with the type, not the value, so at a minimum you're looking at TypeError and ValueError - and those are the only exceptions raised in my patch.(I'll note that my patch does not accept bytes, though this is something of an artificial limitation, since the patch makes use of the fact that all valid isoformat() strings will contain at most exactly 1 non-ascii character in position 10, so we could easily work around this, but I think the trend for CPython is to avoid blurring the lines between bytes and str rather than encouraging their interchangeable use.)
deronnax commentedon Dec 13, 2017
I finally released my work. It looks like Paul's work is more comprehensive, but if you want to pick one thing or two in mine, feel free.
vadmium commentedon Dec 18, 2017
Regarding Matthieu’s RFC 3339 parser, Victor wanted to use the round-half-to-even rule to get a whole number of microseconds. But considering the “time” class cannot represent 24:00, how do you round up in the extreme case past 23:59?
Perhaps it is better to always truncate to zero, only support 6 digits (rejecting fractions of a microsecond), or add Anders’s truncate_microseconds=True option.
pganssle commentedon Dec 18, 2017
@martin.panter I don't see the problem here? Wouldn't 23:59.9999995 round up to 00:00?
vadmium commentedon Dec 18, 2017
Not if the time is associated with a particular day. Imagine implementing datetime.fromisoformat by separately calling date.fromisoformat and time.fromisoformat. The date will be off by one day if you naively rounded 2017-12-18 23:59 “up” to 2017-12-18 00:00.
pganssle commentedon Dec 18, 2017
Yes, I suppose this is a problem if you implement it that way. Seems like a somewhat moot point, but I think any decision about rounding should probably be driven by what people are expecting more than by how it is implemented.
That said, I can see a good case for truncation *and* rounding up for something like '2016-12-31T23:59:59.999999999'. Rounding up to '2017-01-01' is certainly the closest whole millisecond to round to, *but* often people expressing a "23:59:59.9999999" are trying to actually express "the last possible moment *before* 00:00".
jaitaiwan commentedon Dec 19, 2017
I wanted to note here... I've been trying to get strptime to work with the types of dates specified in this request and came across a documentation bug here: https://docs.python.org/3.5/library/time.html#time.strptime
You can see that the %z attribute's examples given have colons in them while the format specified is +HHMM rather than +HH:MM which the examples illude to.
abalkin commentedon Dec 21, 2017
New changeset 09dc2f5 by Alexander Belopolsky (Paul Ganssle) in branch 'master':
bpo-15873: Implement [date][time].fromisoformat (bpo-4699)
09dc2f5
deronnax commentedon Dec 29, 2017
maybe it's worth adding an entry in python 3.7 "what's new" ? I think it was a very long awaited issue.
The opposite of isoformat() is a very frequent question from python newcomers
bitdancer commentedon Dec 29, 2017
Correct, a new feature should always get a what's new entry. You could submit a PR for it :)
abalkin commentedon Feb 6, 2018
New changeset 22864bc by Alexander Belopolsky (Paul Ganssle) in branch 'master':
Add What's new entry for datetime.fromisoformat (bpo-5559)
22864bc
abalkin commentedon Mar 1, 2018
New changeset 0e06be8 by Alexander Belopolsky (Miss Islington (bot)) in branch '3.7':
Add What's new entry for datetime.fromisoformat (GH-5559) (GH-5939)
0e06be8