python / cpython

The Python programming language
https://www.python.org
Other
61.96k stars 29.79k forks source link

Let strptime accept %:z #121237

Open za3k opened 1 month ago

za3k commented 1 month ago

Bug report

Bug description:

https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes documents "strftime() and strptime() Format Codes". It mentions the new %:z variant of %z, introduced in Python 3.12

>>> datetime.datetime.strptime("2023-07-17T13:58:49-07:00", "%Y-%m-%dT%H:%M:%S%z")
datetime.datetime(2023, 7, 17, 13, 58, 49, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=61200)))
>>> datetime.datetime.strptime("2023-07-17T13:58:49-07:00", "%Y-%m-%dT%H:%M:%S%:z")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.12/_strptime.py", line 554, in _strptime_datetime
    tt, fraction, gmtoff_fraction = _strptime(data_string, format)
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/_strptime.py", line 325, in _strptime
    raise ValueError("'%s' is a bad directive in format '%s'" %
ValueError: ':' is a bad directive in format '%Y-%m-%dT%H:%M:%S%:z'

But passing "%:z" to strptime raises an error. This is a bug because strptime and strftime should have the same format codes, according to the docs.

Since %z already parses this format when passed to strptime, I think %:z should just do the same thing.

Workaround: Change %:z to %z in your format string for strptime.

CPython versions tested on:

3.12

Operating systems tested on:

Linux

Linked PRs

nineteendo commented 1 month ago

Wouldn't %:z have to reject -0400?

za3k commented 1 month ago

Reasonable question. Shouldn't %z reject -04:00? It doesn't, currently.

Both should parse the alternative format, or neither, for the sake of consistency.

The current behavior for %z is old (predates %:z from 3.12). I would argue for both to avoid breaking backwards compatibility.

nineteendo commented 1 month ago

In my view : is optional for %z, so it's not used in strftime(), while it's required in %:z. If we enforce this, this actually allows something new instead of an alternative way to do it:

There should be one-- and preferably only one --obvious way to do it.

This should probably be labeled as a new feature.

za3k commented 1 month ago

I think either implementation would be an improvement. I raise no objection :)

nineteendo commented 1 month ago

@Eclips4 can you add the feature label?

LucasEsposito commented 1 month ago

I'll be taking care of this one

As dicussed, we need to have consistency across strptime and strftime, while keeping backwards compatibility.

LucasEsposito commented 1 month ago

I added a PR addressing the issue: https://github.com/python/cpython/pull/122142