From d87b20a3cb277f549f0ba96f12df57183cf8de9d Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google LLC]" Date: Fri, 1 Mar 2024 07:58:14 +0000 Subject: [PATCH 1/5] 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. --- Doc/library/datetime.rst | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 4602132f37f733..14b9ea70ff5f10 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -2525,7 +2525,24 @@ Broadly speaking, ``d.strftime(fmt)`` acts like the :mod:`time` module's For the :meth:`.datetime.strptime` class method, the default value is ``1900-01-01T00:00:00.000``: any components not specified in the format string -will be pulled from the default value. [#]_ +will be pulled from the default value. + +.. note:: + When used to parse partial dates lacking a year, :meth:`~.datetime.strptime` + will raise when encountering February 29 because its default year of 1900 is + *not* a leap year. Always add a default leap year to partial date strings + before parsing:: + + .. doctest:: + + >>> from datetime import datetime + >>> value = "2/29" + >>> datetime.strptime(value, "%m/%d") + Traceback (most recent call last): + ... + ValueError: day is out of range for month + >>> datetime.strptime(f"1904 {value}", "%Y %m/%d") + datetime.datetime(1904, 2, 29, 0, 0) Using ``datetime.strptime(date_string, format)`` is equivalent to:: @@ -2651,6 +2668,11 @@ Notes: for formats ``%d``, ``%m``, ``%H``, ``%I``, ``%M``, ``%S``, ``%j``, ``%U``, ``%W``, and ``%V``. Format ``%y`` does require a leading zero. +(10) + Parsing dates without a year using :meth:`~.datetime.strptime` will fail on + representations of February 29 as that date does not exist in the default + year of 1900. + .. rubric:: Footnotes .. [#] If, that is, we ignore the effects of Relativity @@ -2664,5 +2686,3 @@ Notes: .. [#] See R. H. van Gent's `guide to the mathematics of the ISO 8601 calendar `_ for a good explanation. - -.. [#] Passing ``datetime.strptime('Feb 29', '%b %d')`` will fail since ``1900`` is not a leap year. From 11f01a313a2d2f0ff09546dae87ffb2a5323fc28 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google LLC]" Date: Fri, 1 Mar 2024 08:25:25 +0000 Subject: [PATCH 2/5] doctest code within note is bad, dedent. --- Doc/library/datetime.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 14b9ea70ff5f10..81850f3e288187 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -2531,18 +2531,18 @@ will be pulled from the default value. When used to parse partial dates lacking a year, :meth:`~.datetime.strptime` will raise when encountering February 29 because its default year of 1900 is *not* a leap year. Always add a default leap year to partial date strings - before parsing:: + before parsing. - .. doctest:: +.. doctest:: - >>> from datetime import datetime - >>> value = "2/29" - >>> datetime.strptime(value, "%m/%d") - Traceback (most recent call last): - ... - ValueError: day is out of range for month - >>> datetime.strptime(f"1904 {value}", "%Y %m/%d") - datetime.datetime(1904, 2, 29, 0, 0) + >>> from datetime import datetime + >>> value = "2/29" + >>> datetime.strptime(value, "%m/%d") + Traceback (most recent call last): + ... + ValueError: day is out of range for month + >>> datetime.strptime(f"1904 {value}", "%Y %m/%d") + datetime.datetime(1904, 2, 29, 0, 0) Using ``datetime.strptime(date_string, format)`` is equivalent to:: From 4860a009cd824f90fcbd613d0c4663e37aab8ab8 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Fri, 21 Mar 2025 03:59:46 +0000 Subject: [PATCH 3/5] Update to match the error message. --- Doc/library/datetime.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 513f32d0710d6e..efd25a1d195b41 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -2635,7 +2635,7 @@ will be pulled from the default value. >>> datetime.strptime(value, "%m/%d") Traceback (most recent call last): ... - ValueError: day is out of range for month + ValueError: day 29 must be in range 1..28 for month 2 in year 1900 >>> datetime.strptime(f"1904 {value}", "%Y %m/%d") datetime.datetime(1904, 2, 29, 0, 0) From 9c0d4f84ba56b9a89df1a7643e41b083e7530f3b Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Fri, 21 Mar 2025 04:09:38 +0000 Subject: [PATCH 4/5] remove no longer referenced footnote --- Doc/library/datetime.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index efd25a1d195b41..7eb4d4336f72c4 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -2795,5 +2795,3 @@ Notes: .. [#] See R. H. van Gent's `guide to the mathematics of the ISO 8601 calendar `_ for a good explanation. - -.. [#] Passing ``datetime.strptime('Feb 29', '%b %d')`` will fail since 1900 is not a leap year. From 8c6fd9b0b5b51146d04c0a0cdbe978fcbaa10fc4 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Fri, 21 Mar 2025 04:39:40 +0000 Subject: [PATCH 5/5] ignore the warning in the doctest --- Doc/library/datetime.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 7eb4d4336f72c4..b8721e17311871 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -2631,8 +2631,12 @@ will be pulled from the default value. .. doctest:: >>> from datetime import datetime + >>> import warnings >>> value = "2/29" - >>> datetime.strptime(value, "%m/%d") + >>> with warnings.catch_warnings(): + ... warnings.simplefilter("ignore") + ... datetime.strptime(value, "%m/%d") + ... Traceback (most recent call last): ... ValueError: day 29 must be in range 1..28 for month 2 in year 1900 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy