-1

I have a list of sub-times and a total time. I'm trying to iteratively subtract the sub-times from the total time until I have the remaining time difference after subtracting all the sub-times from the total

Issue is that I'm working with the Python datetime module which seems to be very finicky about formatting. The total time is initially in minutes, seconds, and milliseconds, but after subtracting a lot of the sub-times, it'll change. The sub-time may also be minutes, seconds, milliseconds or simply seconds and milliseconds depending on user input.

I've also been having issues converting the times to datetime objects since they are originally strings and don't adhere fully to datetime formatting.

How would I go about solving this problem?

def convert_to_timedelta(time_string):
    try:
        return datetime.strptime(time_string, '%H:%M:%S.%f') - datetime(1900, 1, 1)
    except ValueError:
        return datetime.strptime(time_string, '%M:%S.%f') - datetime(1900, 1, 1)
    except:
        return timedelta(seconds=float(time_string))

def calculate_remaining_time(total_time, sub_times):
    total_time = convert_to_timedelta(total_time)
    for sub_time in sub_times:
        total_time -= convert_to_timedelta(sub_time)
    return total_time
wjandrea
  • 28,235
  • 9
  • 60
  • 81
penguin
  • 11
  • 5
  • If it were me, since I have the best notion of the exact format, I would just do the time parsing by hand, and produce a seconds value to pass to `timedelta`. Times are not all that hard to parse. – Tim Roberts Aug 01 '23 at 23:43
  • First, make a [mre]. It's hard to help without seeing example input, desired output, and current output. BTW, if you want more tips, check out [ask]. – wjandrea Aug 01 '23 at 23:44
  • Beside the point, but [a bare `except` is bad practice](/q/54948548/4518341). Instead, use the specific exception you're expecting like `except ValueError`. – wjandrea Aug 01 '23 at 23:45

1 Answers1

0

Here is code to parse the strings by hand. This will handle [[HH:]:MM]:SS[.FFF] with any number of digits in between.

I just go through the string one character at a time. When I encounter punctuation, I push the current accumulator on a stack. I also remember if I found a dot. At the bottom, I just combine all the pieces into one "seconds" value.

from  datetime import timedelta

def convert_to_timedelta(time_string):
    value = []
    accum = 0
    dot = False
    for c in time_string:
        if c.isdigit():
            accum = accum * 10 + int(c)
        else:
            value.append(accum)
            dot = c == '.'
            accum = 0
    value.append(accum)
    ms = 0 if not dot else value.pop()
    accum = 0
    for v in value:
        accum = accum * 60 + v
    return timedelta(seconds=accum + ms/1000)

print(convert_to_timedelta('1:22:33'))
print(convert_to_timedelta('1:22:33.123'))
print(convert_to_timedelta('22:33'))
print(convert_to_timedelta('22:33.123'))
print(convert_to_timedelta('33'))
print(convert_to_timedelta('33.123'))

Output:

1:22:33
1:22:33.123000
0:22:33
0:22:33.123000
0:00:33
0:00:33.123000
Tim Roberts
  • 48,973
  • 4
  • 21
  • 30