Skip to content

Commit 2129e53

Browse files
ericfrederichsdispater
authored andcommitted
Incorporate microseconds into averages (#142)
Fixes issue #137
1 parent fcec751 commit 2129e53

File tree

2 files changed

+64
-11
lines changed

2 files changed

+64
-11
lines changed

pendulum/pendulum.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1769,7 +1769,8 @@ def average(self, dt=None):
17691769
if dt is None:
17701770
dt = Pendulum.now(self._tz)
17711771

1772-
return self.add(seconds=int(self.diff(dt, False).in_seconds() / 2))
1772+
diff = self.diff(dt, False)
1773+
return self.add(microseconds=(diff.in_seconds() * 1000000 + diff.microseconds) // 2)
17731774

17741775
def _get_datetime(self, value, pendulum=False):
17751776
"""

tests/pendulum_tests/test_start_end_of.py

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# -*- coding: utf-8 -*-
22

3-
from pendulum import Pendulum
3+
from itertools import product, tee
44

5+
from pendulum import Pendulum
56
from .. import AbstractTestCase
67

78

@@ -208,19 +209,70 @@ def test_average_is_fluid(self):
208209
self.assertIsInstanceOfPendulum(d)
209210

210211
def test_average_from_same(self):
211-
d1 = Pendulum.create(2000, 1, 31, 2, 3, 4)
212-
d2 = Pendulum.create(2000, 1, 31, 2, 3, 4).average(d1)
213-
self.assertPendulum(d2, 2000, 1, 31, 2, 3, 4)
212+
d1 = Pendulum.create(2000, 1, 31, 2, 3, 4, 5)
213+
d2 = Pendulum.create(2000, 1, 31, 2, 3, 4, 5).average(d1)
214+
self.assertPendulum(d2, 2000, 1, 31, 2, 3, 4, 5)
214215

215216
def test_average_from_greater(self):
216-
d1 = Pendulum.create(2000, 1, 1, 1, 1, 1, tz='local')
217-
d2 = Pendulum.create(2009, 12, 31, 23, 59, 59, tz='local').average(d1)
218-
self.assertPendulum(d2, 2004, 12, 31, 12, 30, 30)
217+
d1 = Pendulum.create(2000, 1, 1, 1, 1, 1, 1, tz='local')
218+
d2 = Pendulum.create(2009, 12, 31, 23, 59, 59, 999999, tz='local').average(d1)
219+
self.assertPendulum(d2, 2004, 12, 31, 12, 30, 30, 500000)
219220

220221
def test_average_from_lower(self):
221-
d1 = Pendulum.create(2009, 12, 31, 23, 59, 59, tz='local')
222-
d2 = Pendulum.create(2000, 1, 1, 1, 1, 1, tz='local').average(d1)
223-
self.assertPendulum(d2, 2004, 12, 31, 12, 30, 30)
222+
d1 = Pendulum.create(2009, 12, 31, 23, 59, 59, 999999, tz='local')
223+
d2 = Pendulum.create(2000, 1, 1, 1, 1, 1, 1, tz='local').average(d1)
224+
self.assertPendulum(d2, 2004, 12, 31, 12, 30, 30, 500000)
225+
226+
def test_average_with_microseconds(self):
227+
for d1, d2, expected_average in [
228+
# 3ms and 5ms should average to 4
229+
((1982, 12, 4, 17, 13, 0, 3), (1982, 12, 4, 17, 13, 0, 5), (1982, 12, 4, 17, 13, 0, 4)),
230+
# 999999ms and subsequent 1ms should average to 0
231+
((1982, 12, 4, 0, 0, 0, 999999), (1982, 12, 4, 0, 0, 1, 1), (1982, 12, 4, 0, 0, 1, 0)),
232+
# 1.000002 should average to 0.500001
233+
((2000, 1, 1, 0, 0, 0, 0), (2000, 1, 1, 0, 0, 1, 2), (2000, 1, 1, 0, 0, 0, 500001)),
234+
]:
235+
d1 = Pendulum.create(*d1)
236+
d2 = Pendulum.create(*d2)
237+
a1 = d1.average(d2)
238+
a2 = d2.average(d1)
239+
self.assertPendulum(a1, *expected_average)
240+
self.assertPendulum(a2, *expected_average)
241+
242+
def test_average_commutative(self):
243+
for d1, d2 in product(*tee([
244+
Pendulum.create(1981, 10, 9, 1, 2, 3, 4),
245+
Pendulum.create(1982, 12, 4, 5, 6, 7, 8),
246+
Pendulum.create(2013, 4, 13, 9, 10, 11, 12),
247+
Pendulum.create(1982, 9, 24, 13, 14, 15, 16),
248+
])):
249+
a1 = d1.average(d2)
250+
a2 = d2.average(d1)
251+
self.assertEqual(a1, a2)
252+
253+
def test_bisect_creates_all_times(self):
254+
255+
def bisect(start, end):
256+
# should generate, in order, all microseconds between start and end
257+
mid = start.average(end)
258+
if mid == start or mid == end:
259+
return
260+
for d in bisect(start, mid):
261+
yield d
262+
yield mid
263+
for d in bisect(mid, end):
264+
yield d
265+
266+
start = Pendulum.now()
267+
end = start.add(microseconds=1000)
268+
d_next = start.copy()
269+
n_values = 0
270+
for d in bisect(start, end):
271+
n_values += 1
272+
d_next = d_next.add(microseconds=1)
273+
self.assertEqual(d, d_next)
274+
275+
self.assertEqual(n_values, 999)
224276

225277
def start_of_with_invalid_unit(self):
226278
self.assertRaises(ValueError, Pendulum.now().start_of('invalid'))

0 commit comments

Comments
 (0)