FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

datetime.time.strftime('%Y') raises AttributeError in the pure-Python implementation · Issue #152305 · python/cpython · GitHub

Repository navigation

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

Closed

Description

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

Activity

  1. added
    stdlibStandard Library Python modules in the Lib/ directory
    type-bugAn unexpected behavior, bug, or error
    triagedThe issue has been accepted as valid by a triager.
    on Jun 26, 2026
  2. eendebakpt commented on Jun 26, 2026

    Contributor

    I can confirm the issue on 3.14+ (3.13 is not affected I think). The PR just opened seems like a good solution.

  3. StanFromIreland commented on Jun 26, 2026

    Member

    @eendebakpt the backport labels work only on PRs. I'll review this tomorrow.

  4. StanFromIreland commented on Jun 27, 2026

    Member

    Bisects to 6d34938.

  5. added
    3.14bugs and security fixes
    3.15bugs and security fixes
    3.16new features, bugs and security fixes
    on Jun 27, 2026
  6. added a commit that references this issue on Jun 27, 2026
  7. StanFromIreland commented on Jun 27, 2026

    Member

    Merged, thanks.

  8. added 2 commits that reference this issue on Jun 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixes3.15bugs and security fixes3.16new features, bugs and security fixesstdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


    Back | FazBrowse Home | New Git URL