Skip to content

Commit 5d1d53d

Browse files
Benedikts suggestions
1 parent 0a3e67b commit 5d1d53d

File tree

5 files changed

+26
-17
lines changed

5 files changed

+26
-17
lines changed

Doc/library/datetime.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2432,7 +2432,7 @@ Class attributes:
24322432

24332433
:class:`date`, :class:`.datetime`, and :class:`.time` objects all support a
24342434
``strftime(format)`` method, to create a string representing the time under the
2435-
control of an explicit format string.
2435+
control of an explicit format string. The methods only accept ASCII digits.
24362436

24372437
Conversely, the :meth:`date.strptime`, :meth:`datetime.strptime` and
24382438
:meth:`time.strptime` class methods create an object from a string
@@ -2611,6 +2611,9 @@ differences between platforms in handling of unsupported format specifiers.
26112611
.. versionadded:: 3.12
26122612
``%:z`` was added.
26132613

2614+
.. versionchanged:: next
2615+
Digits must be ASCII
2616+
26142617
Technical Detail
26152618
^^^^^^^^^^^^^^^^
26162619

Doc/whatsnew/3.14.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,11 @@ datetime
504504
* Add :meth:`datetime.time.strptime` and :meth:`datetime.date.strptime`.
505505
(Contributed by Wannes Boeykens in :gh:`41431`.)
506506

507+
* The ``strptime(format)`` methods: :meth:`datetime.date.strptime`,
508+
:meth:`datetime.datetime.strptime` and :meth:`datetime.time.strptime`
509+
only accept ASCII digits.
510+
(Contributed by Stan Ulbrych in :gh:`131008`
511+
507512
decimal
508513
-------
509514

Lib/_strptime.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -286,23 +286,23 @@ def __init__(self, locale_time=None):
286286
base = super()
287287
mapping = {
288288
# The " [1-9]" part of the regex is to make %c from ANSI C work
289-
'd': r"(?P<d>3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])",
289+
'd': r"(?P<d>3[0-1]|[1-2][0-9]|0[1-9]|[1-9]| [1-9])",
290290
'f': r"(?P<f>[0-9]{1,6})",
291-
'H': r"(?P<H>2[0-3]|[0-1]\d|\d)",
291+
'H': r"(?P<H>2[0-3]|[0-1][0-9]|[0-9])",
292292
'I': r"(?P<I>1[0-2]|0[1-9]|[1-9]| [1-9])",
293-
'G': r"(?P<G>\d\d\d\d)",
294-
'j': r"(?P<j>36[0-6]|3[0-5]\d|[1-2]\d\d|0[1-9]\d|00[1-9]|[1-9]\d|0[1-9]|[1-9])",
293+
'G': r"(?P<G>[0-9][0-9][0-9][0-9])",
294+
'j': r"(?P<j>36[0-6]|3[0-5][0-9]|[1-2][0-9][0-9]|0[1-9][0-9]|00[1-9]|[1-9][0-9]|0[1-9]|[1-9])",
295295
'm': r"(?P<m>1[0-2]|0[1-9]|[1-9])",
296-
'M': r"(?P<M>[0-5]\d|\d)",
297-
'S': r"(?P<S>6[0-1]|[0-5]\d|\d)",
298-
'U': r"(?P<U>5[0-3]|[0-4]\d|\d)",
296+
'M': r"(?P<M>[0-5][0-9]|[0-9])",
297+
'S': r"(?P<S>6[0-1]|[0-5][0-9]|[0-9])",
298+
'U': r"(?P<U>5[0-3]|[0-4][0-9]|[0-9])",
299299
'w': r"(?P<w>[0-6])",
300300
'u': r"(?P<u>[1-7])",
301-
'V': r"(?P<V>5[0-3]|0[1-9]|[1-4]\d|\d)",
301+
'V': r"(?P<V>5[0-3]|0[1-9]|[1-4][0-9]|[0-9])",
302302
# W is set below by using 'U'
303-
'y': r"(?P<y>\d\d)",
304-
'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))",
303+
'y': r"(?P<y>[0-9][0-9])",
304+
'Y': r"(?P<Y>[0-9][0-9][0-9][0-9])",
305+
'z': r"(?P<z>[+-][0-9][0-9]:?[0-5][0-9](:?[0-5][0-9](\.[0-9]{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'),
@@ -313,8 +313,8 @@ def __init__(self, locale_time=None):
313313
'Z'),
314314
'%': '%'}
315315
for d in 'dmyHIMS':
316-
mapping['O' + d] = r'(?P<%s>\d\d|\d| \d)' % d
317-
mapping['Ow'] = r'(?P<w>\d)'
316+
mapping['O' + d] = r'(?P<%s>[0-9][0-9]|[0-9]| [0-9])' % d
317+
mapping['Ow'] = r'(?P<w>[0-9])'
318318
mapping['W'] = mapping['U'].replace('U', 'W')
319319
base.__init__(mapping)
320320
base.__setitem__('X', self.pattern(self.locale_time.LC_time))
@@ -380,7 +380,7 @@ def repl(m):
380380

381381
def compile(self, format):
382382
"""Return a compiled re object for the format string."""
383-
return re_compile(self.pattern(format), ASCII | IGNORECASE)
383+
return re_compile(self.pattern(format), IGNORECASE)
384384

385385
_cache_lock = _thread_allocate_lock()
386386
# DO NOT modify _TimeRE_cache or _regex_cache without acquiring the cache lock

Lib/test/datetimetester.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4039,7 +4039,7 @@ def test_strptime_tz(self):
40394039
self.assertEqual(strptime("UTC", "%Z").tzinfo, None)
40404040

40414041
def test_strptime_errors(self):
4042-
for tzstr in ("-2400", "-000", "z"):
4042+
for tzstr in ("-2400", "-000", "z", "٢"):
40434043
with self.assertRaises(ValueError):
40444044
self.theclass.strptime(tzstr, "%z")
40454045

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
:func:`datetime.datetime.strptime` now only accepts ASCII input.
1+
:meth:`datetime.date.strptime`, :meth:`datetime.datetime.strptime` and
2+
:meth:`datetime.time.strptime` now only accept ASCII digits.

0 commit comments

Comments
 (0)