gh-122272: Guarantee specifiers %F and %C for datetime.strftime to be 0-padded (GH-122436)

This commit is contained in:
blhsing 2024-08-23 23:45:03 +08:00 committed by GitHub
parent 7cd3aa42f0
commit 126910edba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 145 additions and 14 deletions

View file

@ -215,6 +215,17 @@ def _need_normalize_century():
_normalize_century = True
return _normalize_century
_supports_c99 = None
def _can_support_c99():
global _supports_c99
if _supports_c99 is None:
try:
_supports_c99 = (
_time.strftime("%F", (1900, 1, 1, 0, 0, 0, 0, 1, 0)) == "1900-01-01")
except ValueError:
_supports_c99 = False
return _supports_c99
# Correctly substitute for %z and %Z escapes in strftime formats.
def _wrap_strftime(object, format, timetuple):
# Don't call utcoffset() or tzname() unless actually needed.
@ -272,14 +283,20 @@ def _wrap_strftime(object, format, timetuple):
# strftime is going to have at this: escape %
Zreplace = s.replace('%', '%%')
newformat.append(Zreplace)
elif ch in 'YG' and object.year < 1000 and _need_normalize_century():
# Note that datetime(1000, 1, 1).strftime('%G') == '1000' so
# year 1000 for %G can go on the fast path.
# Note that datetime(1000, 1, 1).strftime('%G') == '1000' so
# year 1000 for %G can go on the fast path.
elif ((ch in 'YG' or ch in 'FC' and _can_support_c99()) and
object.year < 1000 and _need_normalize_century()):
if ch == 'G':
year = int(_time.strftime("%G", timetuple))
else:
year = object.year
push('{:04}'.format(year))
if ch == 'C':
push('{:02}'.format(year // 100))
else:
push('{:04}'.format(year))
if ch == 'F':
push('-{:02}-{:02}'.format(*timetuple[1:3]))
else:
push('%')
push(ch)