Skip to content

Commit 78fdc33

Browse files
authored
Fix errors where hours and days were not handled correctly when adding durations (#775)
Fixes #768
1 parent 0a884dd commit 78fdc33

File tree

3 files changed

+29
-5
lines changed

3 files changed

+29
-5
lines changed

src/pendulum/datetime.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -685,9 +685,7 @@ def _add_timedelta_(self, delta: datetime.timedelta) -> Self:
685685
microseconds=delta.microseconds,
686686
)
687687
elif isinstance(delta, pendulum.Duration):
688-
return self.add(
689-
years=delta.years, months=delta.months, seconds=delta._total
690-
)
688+
return self.add(**delta._signature) # type: ignore[attr-defined]
691689

692690
return self.add(seconds=delta.total_seconds())
693691

src/pendulum/duration.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,17 @@ def __new__(
112112
self._months = months
113113
self._years = years
114114

115+
self._signature = { # type: ignore[attr-defined]
116+
"years": years,
117+
"months": months,
118+
"weeks": weeks,
119+
"days": days,
120+
"hours": hours,
121+
"minutes": minutes,
122+
"seconds": seconds,
123+
"microseconds": microseconds + milliseconds * 1000,
124+
}
125+
115126
return self
116127

117128
def total_minutes(self) -> float:
@@ -440,7 +451,10 @@ def __mod__(self, other: timedelta) -> Self:
440451

441452
def __divmod__(self, other: timedelta) -> tuple[int, Duration]:
442453
if isinstance(other, timedelta):
443-
q, r = divmod(self._to_microseconds(), other._to_microseconds()) # type: ignore[attr-defined] # noqa: E501
454+
q, r = divmod(
455+
self._to_microseconds(),
456+
other._to_microseconds(), # type: ignore[attr-defined]
457+
)
444458

445459
return q, self.__class__(0, 0, r)
446460

tests/datetime/test_add.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,13 +252,25 @@ def test_add_time_to_new_transition_repeated_big():
252252
assert not dt.is_dst()
253253

254254

255-
def test_add_interval():
255+
def test_add_duration_across_transition():
256256
dt = pendulum.datetime(2017, 3, 11, 10, 45, tz="America/Los_Angeles")
257257
new = dt + pendulum.duration(hours=24)
258258

259259
assert_datetime(new, 2017, 3, 12, 11, 45)
260260

261261

262+
def test_add_duration_across_transition_days():
263+
dt = pendulum.datetime(2017, 3, 11, 10, 45, tz="America/Los_Angeles")
264+
new = dt + pendulum.duration(days=1)
265+
266+
assert_datetime(new, 2017, 3, 12, 10, 45)
267+
268+
dt = pendulum.datetime(2023, 11, 5, 0, 0, tz="America/Chicago")
269+
new = dt + pendulum.duration(days=1)
270+
271+
assert_datetime(new, 2023, 11, 6, 0, 0)
272+
273+
262274
def test_interval_over_midnight_tz():
263275
start = pendulum.datetime(2018, 2, 25, tz="Europe/Paris")
264276
end = start.add(hours=1)

0 commit comments

Comments
 (0)