Skip to content
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

gh-80010: Expand fromisoformat to include most of ISO-8601 #92177

Merged
merged 42 commits into from
May 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
7635fe1
TEMP: Add isoformatter test
pganssle Oct 21, 2021
b9b7a03
Add support for YYYYMMDD
pganssle Oct 21, 2021
c746b96
Expand support for ISO 8601 times
pganssle Oct 21, 2021
00978f9
Add support for ISO calendar-style strings
pganssle Oct 22, 2021
c36e306
Rework how string sanitization works
pganssle Oct 22, 2021
0234cae
WIP
pganssle Nov 16, 2021
ee1a7e3
Move Isoformatter into test helper, add date/time tests
pganssle Apr 27, 2022
7d2fd33
Final location for isoformatter and strategies
pganssle Apr 27, 2022
72266c4
Working version of date.isoformat
pganssle Apr 27, 2022
8067af1
Fix failure to set an error
pganssle May 1, 2022
7b9bca5
First version with time parsing allowed
pganssle May 1, 2022
328e781
Add support for leading T in time formatters
pganssle May 1, 2022
4d0e3a9
Fix pure python separator detection in YYYYWwwd
pganssle May 1, 2022
3e600f2
Version with all tests passing
pganssle May 1, 2022
e26f06f
Migrate fromisoformat tests to their own file
pganssle May 2, 2022
1ea0cd1
Fix bug in time parsing logic
pganssle May 2, 2022
1e3577f
s/ssize_t/size_t
pganssle May 2, 2022
6422799
Add fromisoformat example tests
pganssle May 2, 2022
3d24a15
Try to be consistent about use of double quotes in error messages
pganssle May 2, 2022
661b1b0
Update documentation
pganssle May 3, 2022
1defa1d
Remove isoformatter
pganssle May 3, 2022
75de7a4
Update out-of-date comment
pganssle May 3, 2022
07ee419
Only one space
pganssle May 3, 2022
3d0fb7a
Explicitly handle 0-length tzstr
pganssle May 3, 2022
cc8c737
Raise exceptions from None
pganssle May 3, 2022
31bf63e
Add test cases around week 53
pganssle May 3, 2022
5bfb3fc
Add examples around week 53
pganssle May 3, 2022
4879a47
Update docstrings
pganssle May 3, 2022
3cd657f
Add news entry
pganssle May 3, 2022
763d5bb
Add what's new entry
pganssle May 3, 2022
3a06505
Be consistent about ISO 8601
pganssle May 3, 2022
e643f02
Change name of isoformat separator detection function
pganssle May 5, 2022
5046809
Remove 'mode' logic and update comments
pganssle May 5, 2022
90093bf
Fix segfault case
pganssle May 5, 2022
6fc8157
Explicitly cast signed to unsigned
pganssle May 5, 2022
d9a766b
Document that ordinal dates are not supported
pganssle May 5, 2022
04ed787
Remove dead code
pganssle May 5, 2022
6da3e90
Various fixes
pganssle May 5, 2022
92cc0be
Fix example
pganssle May 5, 2022
bec0bee
Add example for time.fromisoformat
pganssle May 5, 2022
aad6011
Fix trailing colon
pganssle May 5, 2022
a33d776
Remove fromisoformat property test
pganssle May 5, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 48 additions & 35 deletions Doc/library/datetime.rst
Original file line number Diff line number Diff line change
Expand Up @@ -526,18 +526,20 @@ Other constructors, all class methods:

.. classmethod:: date.fromisoformat(date_string)

Return a :class:`date` corresponding to a *date_string* given in the format
``YYYY-MM-DD``::
Return a :class:`date` corresponding to a *date_string* given in any valid
pganssle marked this conversation as resolved.
Show resolved Hide resolved
ISO 8601 format, except ordinal dates (e.g. ``YYYY-DDD``)::

>>> from datetime import date
>>> date.fromisoformat('2019-12-04')
datetime.date(2019, 12, 4)

This is the inverse of :meth:`date.isoformat`. It only supports the format
``YYYY-MM-DD``.
>>> date.fromisoformat('20191204')
datetime.date(2019, 12, 4)
>>> date.fromisoformat('2021-W01-1')
datetime.date(2021, 1, 4)

.. versionadded:: 3.7

.. versionchanged:: 3.11
Previously, this method only supported the format ``YYYY-MM-DD``.

.. classmethod:: date.fromisocalendar(year, week, day)

Expand Down Expand Up @@ -710,8 +712,6 @@ Instance methods:
>>> date(2002, 12, 4).isoformat()
'2002-12-04'

This is the inverse of :meth:`date.fromisoformat`.

.. method:: date.__str__()

For a date *d*, ``str(d)`` is equivalent to ``d.isoformat()``.
Expand Down Expand Up @@ -994,31 +994,29 @@ Other constructors, all class methods:

.. classmethod:: datetime.fromisoformat(date_string)

Return a :class:`.datetime` corresponding to a *date_string* in one of the
formats emitted by :meth:`date.isoformat` and :meth:`datetime.isoformat`.

Specifically, this function supports strings in the format:
Return a :class:`.datetime` corresponding to a *date_string* in any valid
ISO 8601 format, with the following exceptions:

.. code-block:: none

YYYY-MM-DD[*HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]]

where ``*`` can match any single character.

.. caution::

This does *not* support parsing arbitrary ISO 8601 strings - it is only intended
as the inverse operation of :meth:`datetime.isoformat`. A more full-featured
ISO 8601 parser, ``dateutil.parser.isoparse`` is available in the third-party package
`dateutil <https://dateutil.readthedocs.io/en/stable/parser.html#dateutil.parser.isoparse>`__.
1. Time zone offsets may have fractional seconds.
pganssle marked this conversation as resolved.
Show resolved Hide resolved
2. The `T` separator may be replaced by any single unicode character.
3. Ordinal dates are not currently supported.
4. Fractional hours and minutes are not supported.

Examples::

>>> from datetime import datetime
>>> datetime.fromisoformat('2011-11-04')
datetime.datetime(2011, 11, 4, 0, 0)
>>> datetime.fromisoformat('20111104')
datetime.datetime(2011, 11, 4, 0, 0)
>>> datetime.fromisoformat('2011-11-04T00:05:23')
datetime.datetime(2011, 11, 4, 0, 5, 23)
>>> datetime.fromisoformat('2011-11-04T00:05:23Z')
datetime.datetime(2011, 11, 4, 0, 5, 23, tzinfo=datetime.timezone.utc)
>>> datetime.fromisoformat('20111104T000523')
datetime.datetime(2011, 11, 4, 0, 5, 23)
>>> datetime.fromisoformat('2011-W01-2T00:05:23.283')
datetime.datetime(2011, 1, 4, 0, 5, 23, 283000)
>>> datetime.fromisoformat('2011-11-04 00:05:23.283')
datetime.datetime(2011, 11, 4, 0, 5, 23, 283000)
>>> datetime.fromisoformat('2011-11-04 00:05:23.283+00:00')
Expand All @@ -1028,6 +1026,10 @@ Other constructors, all class methods:
tzinfo=datetime.timezone(datetime.timedelta(seconds=14400)))

.. versionadded:: 3.7
.. versionchanged:: 3.11
Previously, this method only supported formats that could be emitted by
:meth:`date.isoformat()` or :meth:`datetime.isoformat()`.


.. classmethod:: datetime.fromisocalendar(year, week, day)

Expand Down Expand Up @@ -1763,30 +1765,41 @@ Other constructor:

.. classmethod:: time.fromisoformat(time_string)

Return a :class:`.time` corresponding to a *time_string* in one of the
formats emitted by :meth:`time.isoformat`. Specifically, this function supports
strings in the format:

.. code-block:: none

HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]

.. caution::
Return a :class:`.time` corresponding to a *time_string* in any valid
ISO 8601 format, with the following exceptions:

This does *not* support parsing arbitrary ISO 8601 strings. It is only
intended as the inverse operation of :meth:`time.isoformat`.
1. Time zone offsets may have fractional seconds.
2. The leading `T`, normally required in cases where there may be ambiguity between
a date and a time, is not required.
3. Fractional seconds may have any number of digits (anything beyond 6 will
be truncated).
4. Fractional hours and minutes are not supported.

Examples::

>>> from datetime import time
>>> time.fromisoformat('04:23:01')
datetime.time(4, 23, 1)
>>> time.fromisoformat('T04:23:01')
datetime.time(4, 23, 1)
>>> time.fromisoformat('T042301')
datetime.time(4, 23, 1)
>>> time.fromisoformat('04:23:01.000384')
datetime.time(4, 23, 1, 384)
>>> time.fromisoformat('04:23:01,000')
datetime.time(4, 23, 1, 384)
>>> time.fromisoformat('04:23:01+04:00')
datetime.time(4, 23, 1, tzinfo=datetime.timezone(datetime.timedelta(seconds=14400)))
>>> time.fromisoformat('04:23:01Z')
datetime.time(4, 23, 1, tzinfo=datetime.timezone.utc)
pganssle marked this conversation as resolved.
Show resolved Hide resolved
>>> time.fromisoformat('04:23:01+00:00')
datetime.time(4, 23, 1, tzinfo=datetime.timezone.utc)


.. versionadded:: 3.7
.. versionchanged:: 3.11
Previously, this method only supported formats that could be emitted by
:meth:`time.isoformat()`.


Instance methods:
Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.11.rst
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,14 @@ asyncio
existing stream-based connections to TLS. (Contributed by Ian Good in
:issue:`34975`.)

datetime
--------

* :meth:`datetime.date.fromisoformat`, :meth:`datetime.time.fromisoformat` and
:meth:`datetime.datetime.fromisoformat` can now be used to parse most ISO 8601
formats (barring only those that support fractional hours and minutes).
pganssle marked this conversation as resolved.
Show resolved Hide resolved
(Contributed by Paul Ganssle in :gh:`80010`.)
pganssle marked this conversation as resolved.
Show resolved Hide resolved

fractions
---------

Expand Down
Loading