In the pure-Python datetime implementation (Lib/_pydatetime.py),
datetime.time.strftime() raises AttributeError for the directives %Y, %G,
%C and %F, while the C accelerator returns the correct values. A time has no
date, so strftime fills the 1900-01-01 placeholder, and these directives should
format that placeholder.
time.strftime passes the time object as object (it has no .year) together
with the fixed placeholder timetuple whose year is 1900. Because
object.year < 1000 is evaluated first in the and chain (before
_need_normalize_century()), the AttributeError is raised on every platform,
including ones where _need_normalize_century() is False.
The year actually being formatted is timetuple[0], which equals 1900 for a
time and equals object.year for date/datetime. Using timetuple[0] fixes
time and leaves date/datetime unchanged.
Regression
Introduced by gh-120713 (the %Y/%G normalization branch) and widened to %F
and %C by gh-122272.
Affected versions
3.13+ (pure-Python implementation). The C accelerator is not affected.
Activity
eendebakpt commented on Jun 26, 2026
I can confirm the issue on 3.14+ (3.13 is not affected I think). The PR just opened seems like a good solution.
StanFromIreland commented on Jun 26, 2026
@eendebakpt the backport labels work only on PRs. I'll review this tomorrow.
StanFromIreland commented on Jun 27, 2026
Bisects to 6d34938.
gh-152305: Fix `_pydatetime.time.strftime()` raising on year directiv…
StanFromIreland commented on Jun 27, 2026
Merged, thanks.
[3.14] gh-152305: Fix `_pydatetime.time.strftime()` raising on year d…
[3.15] gh-152305: Fix `_pydatetime.time.strftime()` raising on year d…