Skip to content

Commit f52d56f

Browse files
committed
PEP 8XX: Deprecate timedelta part attributes
1 parent 616c96a commit f52d56f

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed

peps/pep-08XX.rst

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
PEP: 08XX
2+
Title: Deprecate timedelta part attributes
3+
Author: Anton Agestam
4+
Status: Draft
5+
Type: Standards Track
6+
Created: 11-Feb-2026
7+
Python-Version: 3.15
8+
9+
Abstract
10+
========
11+
12+
This PEP proposes the deprecation and eventual removal of the ``.days``,
13+
``.seconds``, and ``.microseconds`` attributes from ``datetime.timedelta``
14+
objects. These attributes expose broken-down, partial pieces of a time
15+
difference, and are a frequent source of bugs for users who mistake them
16+
for unit representations of the total duration. We propose that these attributes
17+
be phased out entirely. Users should instead rely on direct arithmetic with
18+
``timedelta`` objects to extract specific components, eliminating the need to
19+
expose leaked implementation details.
20+
21+
22+
Motivation
23+
==========
24+
25+
A regular problem encountered in Python codebases is the misuse of the
26+
attributes on ``datetime.timedelta`` objects: ``.days``, ``.seconds``, and
27+
``.microseconds``. Their naming easily misleads developers into believing
28+
they represent the full, accumulated value of the object (akin to the
29+
``.total_seconds()`` method). In reality, they represent broken-apart
30+
pieces of a timedelta at different resolutions, which only make up the full
31+
value when added together.
32+
33+
This issue surfaces frequently in code review and causes bugs in production systems.
34+
The documentation for the ``.seconds`` attribute acknowledges this and
35+
even contains a special warning call-out regarding this common mix-up.
36+
37+
Exposing exactly days, seconds, and microseconds is
38+
arbitrary and leaks an implementation detail originating from 32-bit
39+
Python 2 constraints. There is no consistent API access for other logical
40+
time units—such as weeks, hours, minutes, or milliseconds. This also hinders
41+
imaginable evolution of the timedelta type, for instance to support nanosecond
42+
granularity.
43+
44+
45+
Rationale
46+
=========
47+
48+
Rather than attempting to rename the attributes or introduce new tuple-based
49+
accessors, removing them entirely offers the most approachable way forward.
50+
This approach for now avoids the task of designing a new interface for accessing
51+
parts of a ``timedelta``. The existing arithmetic methods are deemed to work
52+
well, but this PEP takes no stance on later introducing new methods to the
53+
``timedelta`` object for improved ergonomics.
54+
55+
The ``datetime`` module already supports floor division between ``timedelta``
56+
objects. The exact equivalent values of the current attributes can be
57+
cleanly and explicitly derived via arithmetic:
58+
59+
* ``td.days`` is equivalent to ``td // timedelta(days=1)``
60+
* ``td.seconds`` is equivalent to ``(td // timedelta(seconds=1)) % 86400``
61+
* ``td.microseconds`` is equivalent to ``(td // timedelta(microseconds=1)) % 10**6``
62+
63+
Using timedelta arithmetic inherently protects the user from unit-confusion.
64+
For example, to check if a delta is greater than 90 days, instead of writing
65+
``if delta.days >= 90:``, the user can write the unambiguous
66+
``if delta >= timedelta(days=90):``.
67+
68+
Removing these attributes also frees the internal representation of
69+
``timedelta`` from its current historical constraints. If precision needs
70+
to be improved in the future, e.g. adding nanosecond support, users could
71+
simply divide by ``timedelta(nanoseconds=1)`` without the core developers
72+
having to design new attributes.
73+
74+
75+
Specification
76+
=============
77+
78+
1. The ``.days``, ``.seconds``, and ``.microseconds`` attributes of
79+
``datetime.timedelta`` will be scheduled for deprecation.
80+
81+
2. A long-term transition plan will be enacted:
82+
* **Phase 1 (Initial 5 years):** The properties will be decorated with
83+
``@deprecated`` (e.g. ``@deprecated("Use timedelta arithmetic instead", category=None)``)
84+
to provide silent warnings that linters, type checkers, and IDEs can
85+
catch and flag to users well ahead of time.
86+
* **Phase 2 (Subsequent 5 years):** The deprecation category will be
87+
upgraded to trigger a runtime ``DeprecationWarning``.
88+
* **Phase 3:** The attributes can be removed completely, in accordance
89+
with the backwards compatibility policy outlined in PEP 387.
90+
91+
3. Official documentation will be updated to recommend ``.total_seconds()``
92+
for total duration, and arithmetic division with ``timedelta`` objects
93+
for unit extraction.
94+
95+
96+
Backwards Compatibility
97+
=======================
98+
99+
Because ``timedelta`` is widely used, deprecating these attributes will
100+
impact existing codebases. To minimize disruption, this PEP stipulates a
101+
long deprecation period as per PEP 387 (totaling 10 years) before ultimate
102+
removal. This follows Python's normal deprecation cycle for widely used
103+
standard library features, ensuring developers have ample time to migrate
104+
without sudden breakage.
105+
106+
107+
Rejected Ideas
108+
==============
109+
110+
Rename attributes to ``.part_days``, ``.part_seconds``, etc.
111+
------------------------------------------------------------
112+
An `initial proposal <https://discuss.python.org/t/rename-alias-and-deprecate-timedelta-part-attributes/97674/1>`_
113+
suggested renaming the attributes to prefix them with ``part_`` to signify
114+
they are incomplete fragments of the duration. This is rejected as the parts
115+
themselves are arbitrary, and eliminating them entirely leaves a clean API. It
116+
is deemed that these properties are not useful enough to warrant being part of
117+
the API, and in the cases they are needed, they can still be calculated.
118+
119+
Return a tuple of internal values
120+
---------------------------------
121+
Suggestions were made to add a method returning the internally stored
122+
values as a tuple, such as `(days, seconds, microseconds) <https://discuss.python.org/t/rename-alias-and-deprecate-timedelta-part-attributes/97674/13>`_,
123+
or a simplified ``(days, seconds)`` where seconds is a float. Others suggested
124+
exporting a `5-tuple: (days, hours, mins, secs, microsecs) <https://discuss.python.org/t/rename-alias-and-deprecate-timedelta-part-attributes/97674/4>`_.
125+
This is similarly rejected due to being deemed of little value to users, as well
126+
as because it exposes an internal implementation detail.
127+
128+
If timedelta precision is later improved to include nanoseconds, the size of the
129+
tuple would have to change. Furthermore, the order of tuple components does not
130+
inherently match constructor arguments. The arithmetic approach is safer and
131+
more flexible.
132+
133+
Keep ``.days`` but deprecate the rest
134+
-------------------------------------
135+
Some `argued <https://discuss.python.org/t/rename-alias-and-deprecate-timedelta-part-attributes/97674/21>`_
136+
that ``.days`` should be kept because it is unbounded and does not have the
137+
exact same "footgun" characteristics as ``.seconds``. This is rejected in part
138+
for the sake of exposing a consistent API, and in part because the days
139+
attribute has other footguns as `was pointed out in the discussion <https://discuss.python.org/t/rename-alias-and-deprecate-timedelta-part-attributes/97674/22>`_:
140+
``timedelta(seconds=-1).days == -1``.
141+
142+
Furthermore, the standard use case for ``.days``
143+
(e.g. ``if delta.days >= 90``) is `better served <https://discuss.python.org/t/rename-alias-and-deprecate-timedelta-part-attributes/97674/8>`_
144+
by unambiguous ``timedelta`` object comparison: ``if delta >= timedelta(days=90)``.
145+
146+
Provide a ``__format__`` method
147+
-------------------------------
148+
A `tangential suggestion <https://discuss.python.org/t/rename-alias-and-deprecate-timedelta-part-attributes/97674/10>`_
149+
highlighted the difficulty of formatting ``timedelta`` objects into
150+
human-readable strings, which often requires breaking down the parts, prompting
151+
a request for a dedicated ``__format__`` method. While formatting is a valid
152+
concern with high community demand, it is an orthogonal issue to the structural
153+
representation of the class. This idea is explicitly deferred to future
154+
independent design improvements of this type and considered out of scope of this
155+
PEP.
156+
157+
Make microseconds a float part of seconds
158+
-----------------------------------------
159+
A `suggestion was raised <https://discuss.python.org/t/rename-alias-and-deprecate-timedelta-part-attributes/97674/12>`_
160+
to eliminate the microseconds attribute by rolling it into seconds as a float.
161+
This was rejected, as it is strictly an implementation detail and does not solve
162+
the overarching issue of users mistaking partial properties for total accumulated
163+
durations.

0 commit comments

Comments
 (0)