10000 gh-122781: Allow empty offset for `%z` in `strptime` (#132922) · python/cpython@99b5808 · GitHub
[go: up one dir, main page]

Skip to content

Commit 99b5808

Browse files
gh-122781: Allow empty offset for %z in strptime (#132922)
* commit * Move tests
1 parent 7ad9046 commit 99b5808

File tree

3 files changed

+36
-22
lines changed

3 files changed

+36
-22
lines changed

Lib/_strptime.py

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ def __init__(self, locale_time=None):
302302
# W is set below by using 'U'
303303
'y': r"(?P<y>\d\d)",
304304
'Y': r"(?P<Y>\d\d\d\d)",
305-
'z': r"(?P<z>[+-]\d\d:?[0-5]\d(:?[0-5]\d(\.\d{1,6})?)?|(?-i:Z))",
305+
'z': r"(?P<z>([+-]\d\d:?[0-5]\d(:?[0-5]\d(\.\d{1,6})?)?)|(?-i:Z))?",
306306
'A': self.__seqToRE(self.locale_time.f_weekday, 'A'),
307307
'a': self.__seqToRE(self.locale_time.a_weekday, 'a'),
308308
'B': self.__seqToRE(self.locale_time.f_month[1:], 'B'),
@@ -548,27 +548,28 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
548548
iso_week = int(found_dict['V'])
549549
elif group_key == 'z':
550550
z = found_dict['z']
551-
if z == 'Z':
552-
gmtoff = 0
553-
else:
554-
if z[3] == ':':
555-
z = z[:3] + z[4:]
556-
if len(z) > 5:
557-
if z[5] != ':':
558-
msg = f"Inconsistent use of : in {found_dict['z']}"
559-
raise ValueError(msg)
560-
z = z[:5] + z[6:]
561-
hours = int(z[1:3])
562-
minutes = int(z[3:5])
563-
seconds = int(z[5:7] or 0)
564-
gmtoff = (hours * 60 * 60) + (minutes * 60) + seconds
565-
gmtoff_remainder = z[8:]
566-
# Pad to always return microseconds.
567-
gmtoff_remainder_padding = "0" * (6 - len(gmtoff_remainder))
568-
gmtoff_fraction = int(gmtoff_remainder + gmtoff_remainder_padding)
569-
if z.startswith("-"):
570-
gmtoff = -gmtoff
571-
gmtoff_fraction = -gmtoff_fraction
551+
if z:
552+
if z == 'Z':
553+
gmtoff = 0
554+
else:
555+
if z[3] == ':':
556+
z = z[:3] + z[4:]
557+
if len(z) > 5:
558+
if z[5] != ':':
559+
msg = f"Inconsistent use of : in {found_dict['z']}"
560+
raise ValueError(msg)
561+
z = z[:5] + z[6:]
562+
hours = int(z[1:3])
563+
minutes = int(z[3:5])
564+
seconds = int(z[5:7] or 0)
565+
gmtoff = (hours * 60 * 60) + (minutes * 60) + seconds
566+
gmtoff_remainder = z[8:]
567+
# Pad to always return microseconds.
568+
gmtoff_remainder_padding = "0" * (6 - len(gmtoff_remainder))
569+
gmtoff_fraction = int(gmtoff_remainder + gmtoff_remainder_padding)
570+
if z.startswith("-"):
571+
gmtoff = -gmtoff
572+
gmtoff_fraction = -gmtoff_fraction
572573
elif group_key == 'Z':
573574
# Since -1 is default value only need to worry about setting tz if
574575
# it can be something other than -1.

Lib/test/datetimetester.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2972,6 +2972,17 @@ def test_strptime_leap_year(self):
29722972
with self._assertNotWarns(DeprecationWarning):
29732973
self.theclass.strptime('02-29,2024', '%m-%d,%Y')
29742974

2975+
def test_strptime_z_empty(self):
2976+
for directive in ('z',):
2977+
string = '2025-04-25 11:42:47'
2978+
format = f'%Y-%m-%d %H:%M:%S%{directive}'
2979+
target = self.theclass(2025, 4, 25, 11, 42, 47)
2980+
with self.subTest(string=string,
2981+
format=format,
2982+
target=target):
2983+
result = self.theclass.strptime(string, format)
2984+
self.assertEqual(result, target)
2985+
29752986
def test_more_timetuple(self):
29762987
# This tests fields beyond those tested by the TestDate.test_timetuple.
29772988
t = self.theclass(2004, 12, 31, 6, 22, 33)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix ``%z`` directive in :func:`datetime.datetime.strptime` to allow for no provided
2+
offset as was documented.

0 commit comments

Comments
 (0)
0