Skip to content

Commit

Permalink
Fix the computation of total seconds with years and months
Browse files Browse the repository at this point in the history
  • Loading branch information
sdispater committed Jul 4, 2020
1 parent 0735ac4 commit 4ab7fb4
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 23 deletions.
11 changes: 2 additions & 9 deletions pendulum/datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,7 @@ def _add_timedelta_(self, delta):
)
elif isinstance(delta, pendulum.Duration):
return self.add(
years=delta.years, months=delta.months, seconds=delta.total_seconds()
years=delta.years, months=delta.months, seconds=delta._total
)

return self.add(seconds=delta.total_seconds())
Expand All @@ -770,14 +770,7 @@ def _subtract_timedelta(self, delta):
"""
if isinstance(delta, pendulum.Duration):
return self.subtract(
years=delta.years,
months=delta.months,
weeks=delta.weeks,
days=delta.remaining_days,
hours=delta.hours,
minutes=delta.minutes,
seconds=delta.remaining_seconds,
microseconds=delta.microseconds,
years=delta.years, months=delta.months, seconds=delta._total
)

return self.subtract(seconds=delta.total_seconds())
Expand Down
26 changes: 12 additions & 14 deletions pendulum/duration.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,19 @@ def __new__(
raise ValueError("Float year and months are not supported")

self = timedelta.__new__(
cls, days, seconds, microseconds, milliseconds, minutes, hours, weeks
cls,
days + years * 365 + months * 30,
seconds,
microseconds,
milliseconds,
minutes,
hours,
weeks,
)

# Intuitive normalization
total = self.total_seconds()
total = self.total_seconds() - (years * 365 + months * 30) * SECONDS_PER_DAY
self._total = total

m = 1
if total < 0:
Expand All @@ -80,7 +88,7 @@ def __new__(
self._seconds = abs(int(total)) % SECONDS_PER_DAY * m

_days = abs(int(total)) // SECONDS_PER_DAY * m
self._days = _days + (years * 365 + months * 30)
self._days = _days
self._remaining_days = abs(_days) % 7 * m
self._weeks = abs(_days) // 7 * m
self._months = months
Expand Down Expand Up @@ -125,10 +133,6 @@ def months(self):
def weeks(self):
return self._weeks

@property
def days(self):
return self._days

@property
def remaining_days(self):
return self._remaining_days
Expand Down Expand Up @@ -320,7 +324,7 @@ def __mul__(self, other):
return self.__class__(
years=self._years * other,
months=self._months * other,
seconds=self.total_seconds() * other,
seconds=self._total * other,
)

if isinstance(other, float):
Expand All @@ -341,9 +345,6 @@ def __floordiv__(self, other):
if isinstance(other, timedelta):
return usec // other._to_microseconds()

# Removing years/months approximation
usec -= (self._years * 365 + self._months * 30) * SECONDS_PER_DAY * 1e6

if isinstance(other, int):
return self.__class__(
0,
Expand All @@ -361,9 +362,6 @@ def __truediv__(self, other):
if isinstance(other, timedelta):
return usec / other._to_microseconds()

# Removing years/months approximation
usec -= (self._years * 365 + self._months * 30) * SECONDS_PER_DAY * 1e6

if isinstance(other, int):
return self.__class__(
0,
Expand Down
2 changes: 2 additions & 0 deletions tests/duration/test_construct.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ def test_years():
pi = pendulum.duration(years=2)
assert_duration(pi, years=2, weeks=0)
assert 730 == pi.days
assert 63072000 == pi.total_seconds()


def test_months():
pi = pendulum.duration(months=3)
assert_duration(pi, months=3, weeks=0)
assert 90 == pi.days
assert 7776000 == pi.total_seconds()


def test_weeks():
Expand Down

0 comments on commit 4ab7fb4

Please sign in to comment.