Skip to content

Commit b8d3fdd

Browse files
authored
gh-70647: Better promote how to safely parse yearless dates in datetime. (GH-116179)
* gh-70647: Better promote how to safely parse yearless dates in datetime. Every four years people encounter this because it just isn't obvious. This moves the footnote up to a note with a code example. We'd love to change the default year value for datetime but doing that could have other consequences for existing code. This documented workaround *always* works. * doctest code within note is bad, dedent. * Update to match the error message. * remove no longer referenced footnote * ignore the warning in the doctest * use Petr's suggestion for the docs to hide the warning processing * cover date.strptime (3.14) as well
1 parent 8d2d7bb commit b8d3fdd

File tree

1 file changed

+37
-6
lines changed

1 file changed

+37
-6
lines changed

Doc/library/datetime.rst

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2651,9 +2651,42 @@ Broadly speaking, ``d.strftime(fmt)`` acts like the :mod:`time` module's
26512651
``time.strftime(fmt, d.timetuple())`` although not all objects support a
26522652
:meth:`~date.timetuple` method.
26532653

2654-
For the :meth:`.datetime.strptime` class method, the default value is
2655-
``1900-01-01T00:00:00.000``: any components not specified in the format string
2656-
will be pulled from the default value. [#]_
2654+
For the :meth:`.datetime.strptime` and :meth:`.date.strptime` class methods,
2655+
the default value is ``1900-01-01T00:00:00.000``: any components not specified
2656+
in the format string will be pulled from the default value.
2657+
2658+
.. note::
2659+
When used to parse partial dates lacking a year, :meth:`.datetime.strptime`
2660+
and :meth:`.date.strptime` will raise when encountering February 29 because
2661+
the default year of 1900 is *not* a leap year. Always add a default leap
2662+
year to partial date strings before parsing.
2663+
2664+
2665+
.. testsetup::
2666+
2667+
# doctest seems to turn the warning into an error which makes it
2668+
# show up and require matching and prevents the actual interesting
2669+
# exception from being raised.
2670+
# Manually apply the catch_warnings context manager
2671+
import warnings
2672+
catch_warnings = warnings.catch_warnings()
2673+
catch_warnings.__enter__()
2674+
warnings.simplefilter("ignore")
2675+
2676+
.. testcleanup::
2677+
2678+
catch_warnings.__exit__()
2679+
2680+
.. doctest::
2681+
2682+
>>> from datetime import datetime
2683+
>>> value = "2/29"
2684+
>>> datetime.strptime(value, "%m/%d")
2685+
Traceback (most recent call last):
2686+
...
2687+
ValueError: day 29 must be in range 1..28 for month 2 in year 1900
2688+
>>> datetime.strptime(f"1904 {value}", "%Y %m/%d")
2689+
datetime.datetime(1904, 2, 29, 0, 0)
26572690

26582691
Using ``datetime.strptime(date_string, format)`` is equivalent to::
26592692

@@ -2790,7 +2823,7 @@ Notes:
27902823
include a year in the format. If the value you need to parse lacks a year,
27912824
append an explicit dummy leap year. Otherwise your code will raise an
27922825
exception when it encounters leap day because the default year used by the
2793-
parser is not a leap year. Users run into this bug every four years...
2826+
parser (1900) is not a leap year. Users run into that bug every leap year.
27942827

27952828
.. doctest::
27962829

@@ -2817,5 +2850,3 @@ Notes:
28172850
.. [#] See R. H. van Gent's `guide to the mathematics of the ISO 8601 calendar
28182851
<https://web.archive.org/web/20220531051136/https://webspace.science.uu.nl/~gent0113/calendar/isocalendar.htm>`_
28192852
for a good explanation.
2820-
2821-
.. [#] Passing ``datetime.strptime('Feb 29', '%b %d')`` will fail since 1900 is not a leap year.

0 commit comments

Comments
 (0)