Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/pendulum/duration.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,14 @@ def __new__(
)

# Intuitive normalization
total = self.total_seconds() - (years * 365 + months * 30) * SECONDS_PER_DAY
# Use timedelta's own total_seconds() rather than self.total_seconds():
# on PyPy the latter is overridden to read _days/_seconds/... which are
# not populated yet at this point, which would zero out the duration
# (see issue #876).
total = (
timedelta.total_seconds(self)
- (years * 365 + months * 30) * SECONDS_PER_DAY
)
self._total = total

m = 1
Expand Down
13 changes: 13 additions & 0 deletions tests/duration/test_construct.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,16 @@ def test_float_years_and_months():

with pytest.raises(ValueError):
pendulum.duration(months=1.5)


def test_new_does_not_depend_on_total_seconds_override(monkeypatch):
# __new__ must derive the duration's total from the underlying timedelta,
# not from a (possibly overridden) total_seconds(). On PyPy, total_seconds()
# is overridden to read _days/_seconds/... which are not populated yet during
# __new__, which zeroed out full-day durations (issue #876).
from pendulum.duration import Duration

monkeypatch.setattr(Duration, "total_seconds", lambda self: 0.0)

assert pendulum.duration(days=1)._total == 86400.0
assert pendulum.duration(hours=23)._total == 82800.0