4

So I have this list:

[datetime.timedelta(0, 1800), datetime.timedelta(0, 1800), datetime.timedelta(0, 1800), datetime.timedelta(0, 1800)]

Collectively that is 2:00 hours. I'm trying to add those up to get 2:00 time delta, which then in turn needs to be turned into a string of 2.0 Hours. Respectively 1:30 Hours would be 1.5 Hours as the final countdown.

Morten Kristensen
  • 7,412
  • 4
  • 32
  • 52
Matthew
  • 837
  • 3
  • 18
  • 33

2 Answers2

4

The naive approach would be to take the seconds from each object and sum them

>>> a = [datetime.timedelta(0, 1800)] * 4
>>> print sum([d.seconds for d in a])
7200
>>> print sum([d.seconds for d in a]) / 60.0 / 60.0
2.0

but this is not as robust as Haidro's solution:

import operator
reduce(operator.add, a)

This results in a timedelta object with the correct delta that you can use however you want.

John Lyon
  • 11,180
  • 4
  • 36
  • 44
  • 3
    Summing `.seconds` is risky. You'll drop hours and microseconds so it's a pretty big assumption not to include them. Either use `.total_seconds()` (python 2.7) or do the math to include hours/microseconds. – Hamish Sep 17 '13 at 22:33
  • Hah! Operator is amazing, you're right better off going that route. By chance how can you remember all these different module so effectively? – Matthew Sep 17 '13 at 22:36
  • @Matthew Heh, well, the operator solution was mine, so I guess I'll answer this. Overtime when answering questions I learn a lot of things, such as built-in functions I've never seen before or awesome modules, such as this one. The `operator` special is nothing special, it's just a simplified version of something else. For example, `operator.add(a, b)` is the same as `a + b`. – TerryA Sep 17 '13 at 22:40
  • 1
    Either version is overkill. You don't have to call `sum` on the `d.total_seconds()` values, when you can just call it directly on the values. And you don't have to build `sum` manually out of `reduce` when you can just use the builtin. – abarnert Sep 18 '13 at 00:59
4

The obvious way to sum anything number-like and addable in Python is with the sum function:

>>> dts = [datetime.timedelta(0, 1800), datetime.timedelta(0, 1800), datetime.timedelta(0, 1800), datetime.timedelta(0, 1800)]
>>> sum(dts, start=datetime.timedelta(0))
datetime.timedelta(0, 9, 933279)

(For most number-like types, you don't even need the start value, because they know how to add themselves to 0. timedelta explicitly does not allow this, to avoid accidentally mixing dimensionless intervals—e.g., you don't want to add timeout_in_millis to a timedelta…)


Whenever you're using reduce with operator.add for number-like values, you're probably doing it wrong.

If you don't provide an initial argument to reduce, it will do the wrong thing with an empty list, raising a TypeError instead of returning the 0 value. (The sum of no numbers is 0; the sum of no timedeltas is timedelta(0); etc.)

And if you do provide an initial argument, then it's just a more verbose, more complicated, and slower way to write sum. Compare:

functools.reduce(operator.add, a, foo(0))
sum(a, foo(0))
abarnert
  • 354,177
  • 51
  • 601
  • 671