Skip to content

datetime.time.strftime('%Y') raises AttributeError in the pure-Python implementation #152305

Description

@tonghuaroot

Bug report

Bug description

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.

>>> import _pydatetime  # pure implementation
>>> _pydatetime.time(12, 30).strftime('%Y')
Traceback (most recent call last):
  ...
  File ".../Lib/_pydatetime.py", line 276, in _wrap_strftime
    object.year < 1000 and _need_normalize_century()):
AttributeError: 'time' object has no attribute 'year'

The C accelerator is correct:

>>> import datetime  # C accelerator
>>> datetime.time(12, 30).strftime('%Y')
'1900'
>>> datetime.time(12, 30).strftime('%C')
'19'
>>> datetime.time(12, 30).strftime('%F')
'1900-01-01'
>>> datetime.time(12, 30).strftime('%G')
'1900'

Date-only directives such as %j already agree between the two implementations
(both give '001').

Root cause

_wrap_strftime(object, format, timetuple) reads object.year in the
year-normalization branch:

elif ((ch in 'YG' or ch in 'FC') and
        object.year < 1000 and _need_normalize_century()):
    ...
    year = object.year

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.

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixes3.15pre-release feature fixes, bugs and security fixes3.16new features, bugs and security fixesstdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error
    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions