Recipe 3.4. Summing Durations of Songs
Credit: Anna Martelli Ravenscroft
Problem
You want to find out the total
duration of a playlist of songs.
Solution
Use
the datetime standard module and the built-in
function sum to handle this
task:
import datetime
def totaltimer(times):
td = datetime.timedelta(0)
# initial value of sum (must be a timedelta)
duration = sum([
datetime.timedelta(minutes=m, seconds=s) for m, s in times],
td)
return duration
if _ _name_ _== '_ _main_ _':
# test when module run as main script
times1 = [(2, 36),
# list containing tuples (minutes, seconds)
(3, 35),
(3, 45),]
times2 = [(3, 0),
(5, 13),
(4, 12),
(1, 10),]
assert totaltimer(times1) == datetime.timedelta(0, 596)
assert totaltimer(times2) == datetime.timedelta(0, 815)
print ("Tests passed.\n"
"First test total: %s\n"
"Second test total: %s" % (
totaltimer(times1), totaltimer(times2)))
Discussion
I have a large playlist of songs I listen to during workouts. I
wanted to create a select list but wanted to know the total duration
of the selected songs, without having to create the new playlist
first. I wrote this little script to handle the task.A datetime.timedelta is normally
what's returned when calculating the difference
between two datetime objects. However, you can
create your own timedelta instance to represent
any given duration of time (while other classes
of the datetime module, such as class
datetime, have instances that represent a
point in time). Here, we need to sum durations,
so, clearly, it's exactly
timedelta that we need.datetime.timedelta takes a variety of optional
arguments: days, seconds, microseconds, milliseconds, minutes, hours,
weeks. So, to create an instance, you really should pass named
arguments when you call the class to avoid confusion. If you simply
call datetime.timedelta(m, n), without naming the
arguments, the class uses positional notation and treats
m and n as days
and seconds, which produces really strange results. (I found this out
the hard way . . . a good demonstration of the need to
test!)To use the built-in function sum on a list of
objects such as timedeltas, you have to pass to
sum a second argument to use as the initial
valueotherwise, the default initial value is
0, integer zero, and you get an error as soon as
you try to sum a timedelta with that
int. All objects in the iterable that you pass as
sum's first argument should be
able to support numeric addition. (Strings are
specifically disallowed, but, take my earnest
advice: don't use
sum for concatenating a lot of lists either!) In
Python 2.4, instead of a list comprehension for
sum's first argument, we could
use a generator expression by replacing the square brackets,
[ and ], with parentheses,
( and )which might be
handy if you're trying to handle a playlist of
several thousand songs.For the test case, I manually created a list of tuples with the
durations of the songs in minutes and seconds. The script could be
enhanced to parse the times in different formats (such as mm:ss) or
to read the information from a file or directly from your music
library.
See Also
Library Reference on sum
and datetime.