summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorblhsing <blhsing@gmail.com>2024-08-23 15:45:03 (GMT)
committerGitHub <noreply@github.com>2024-08-23 15:45:03 (GMT)
commit126910edba812a01794f307b0cfa2a7f02bda190 (patch)
treee86e74c3e38f2b8cfcbe9484dc696a0c52767a3f /Lib
parent7cd3aa42f0cf72bf9a214e2630850879fe078377 (diff)
downloadcpython-126910edba812a01794f307b0cfa2a7f02bda190.zip
cpython-126910edba812a01794f307b0cfa2a7f02bda190.tar.gz
cpython-126910edba812a01794f307b0cfa2a7f02bda190.tar.bz2
gh-122272: Guarantee specifiers %F and %C for datetime.strftime to be 0-padded (GH-122436)
Diffstat (limited to 'Lib')
-rw-r--r--Lib/_pydatetime.py25
-rw-r--r--Lib/test/datetimetester.py17
2 files changed, 34 insertions, 8 deletions
diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py
index 27cacb8..78432d4 100644
--- a/Lib/_pydatetime.py
+++ b/Lib/_pydatetime.py
@@ -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)
diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py
index 38de110..0265643 100644
--- a/Lib/test/datetimetester.py
+++ b/Lib/test/datetimetester.py
@@ -1710,13 +1710,22 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
(1000, 0),
(1970, 0),
)
- for year, offset in dataset:
- for specifier in 'YG':
+ specifiers = 'YG'
+ if _time.strftime('%F', (1900, 1, 1, 0, 0, 0, 0, 1, 0)) == '1900-01-01':
+ specifiers += 'FC'
+ for year, g_offset in dataset:
+ for specifier in specifiers:
with self.subTest(year=year, specifier=specifier):
d = self.theclass(year, 1, 1)
if specifier == 'G':
- year += offset
- self.assertEqual(d.strftime(f"%{specifier}"), f"{year:04d}")
+ year += g_offset
+ if specifier == 'C':
+ expected = f"{year // 100:02d}"
+ else:
+ expected = f"{year:04d}"
+ if specifier == 'F':
+ expected += f"-01-01"
+ self.assertEqual(d.strftime(f"%{specifier}"), expected)
def test_replace(self):
cls = self.theclass