Sum timestamps
Source: Python Morsels
Description
Given a list of timestamps, return their sum. Handle timestamps in either of these formats or a mixture of both:
5:32
1:05:32
Notes
None.
My solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
def sum_timestamps(timestamps):
'''Given a list of timestamps, return their sum.
Takes a list of strings and returns a string. Handles timestamps
in either or both of MM:SS and HH:MM:SS formats.'''
splits = [x.split(':') for x in timestamps]
# Prepend '00' hours to any timestamp that omits hours.
splits = [['00'] + x if len(x) < 3 else x for x in splits]
hrs = [int(x[0]) for x in splits]
mins = [int(x[1]) for x in splits]
secs = [int(x[2]) for x in splits]
# Compute minutes based on seconds.
carry, secs_sum = divmod(sum(secs), 60)
mins_sum = sum(mins) + carry
# Compute hours based on minutes.
try:
oflow = sum(hrs)
except NameError:
oflow = 0
if mins_sum > 59:
carry, mins_sum = divmod(mins_sum, 60)
oflow += carry
# Format and return a string.
ss = str(secs_sum).zfill(2)
mm = str(mins_sum).zfill(2) if oflow else str(mins_sum)
hh = str(oflow) if oflow else ''
return f'{hh}:{mm}:{ss}' if oflow else f'{mm}:{ss}'
## Tests
def test_sum_timestamps_nohrs_nocarry():
assert sum_timestamps(['03:10', '01:00']) == '4:10'
def test_sum_timestamps_nohrs_carry():
assert sum_timestamps(['5:32', '4:48']) == '10:20'
assert sum_timestamps(['2:10', '1:59']) == '4:09'
def test_sum_timestamps_nohrs_overflow():
assert sum_timestamps(['15:32', '45:48']) == '1:01:20'
def test_sum_timestamps_hrs():
assert sum_timestamps(['6:15:32', '2:45:48']) == '9:01:20'
assert sum_timestamps(['6:35:32', '2:45:48', '40:10']) == '10:01:30'
## Interaction
if __name__ == '__main__':
import pytest
print('My tests')
pytest.main([__file__])
print('Pymorsel tests')
from os import system
system('python test_sum_timestamps.py')
Provided solution
The provided solutions all include separate functions for parsing the timestamps, summing them, and formatting the output string. This makes good sense.
The final version of the parsing function uses regexps, which doesn’t seem necessary to me.
One version of the summing function uses the datetime
module.
Given the simplicity of the timestamp format here, that doesn’t
seem necessary either. The final version of the summing function
uses divmod()
, as I did.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import re
TIME_RE = re.compile(r'''
^
(?:
( \d + )
:
)?
( \d + )
:
( \d + )
$
''', re.VERBOSE)
def parse_time(time_string):
hours, minutes, seconds = TIME_RE.search(time_string).groups()
return int(hours or 0)*3600 + int(minutes)*60 + int(seconds)
def format_time(seconds):
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
if hours:
return f"{hours}:{minutes:02d}:{seconds:02d}"
else:
return f"{minutes:01d}:{seconds:02d}"
def sum_timestamps(timestamps):
return format_time(sum(parse_time(t) for t in timestamps))