The datetime.timedelta
could have a side-effect for string representation of negative value, see doc point 5. To Bypass it just define a new class with custom __add__
and __sub__
methods.
Used a boolean flag to distinguish positive from negative "values".
import datetime
class TD:
# Time Delta arithmetics (addition/subtraction only)
def str2td(self, tstr):
# is_positive attribute just care about the minus symbol, hence 00h00 is considered positive
if tstr.startswith('-'):
self.is_positive = False
tstr = tstr.lstrip('-')
else:
self.is_positive = True
return datetime.timedelta(**dict(zip(('hours', 'minutes'), map(int, tstr.split('h')))))
def __init__(self, tstr):
self.tstr = tstr
self.td = self.str2td(tstr)
def __str__(self):
return self.__str_format(str(self.td)) if self.is_positive else self.__str_format(f"-{self.td}")
def __str_format(self, fstr):
# -10:00:00 --> -10h:00
h, m = fstr.split(':')[:2]
return f'{h}h{m}'
def __add__(self, td_new):
if self.is_positive and td_new.is_positive:
return TD(self.__str_format(str(self.td + td_new.td)))
elif not self.is_positive and td_new.is_positive:
if self.td == td_new.td:
return TD('00h00')
elif self.td > td_new.td:
return TD(self.__str_format(f"-{str(self.td - td_new.td)}"))
else:
return TD(self.__str_format(str(td_new.td - self.td)))
elif self.is_positive and not td_new.is_positive:
return td_new + self
else:
return TD(self.__str_format(f"-{str(self.td + td_new.td)}"))
def __sub__(self, td_new):
# change sign of td_new
td_new_opp = f'-{td_new.tstr}' if td_new.is_positive else td_new.tstr.lstrip('-')
return self + TD(td_new_opp)
Here a test:
# auxiliary functions
def check_add(t1, t2):
td1, td2 = TD(t1), TD(t2)
tot = td1 + td2
print(f'{td1} + {td2} = {str(tot)}')
def check_sub(t1, t2):
td1, td2 = TD(t1), TD(t2)
print(f'{td1} - {td2} = {td1 - td2}')
# tests
t1, t2 = "10h00", "5h00"
check_add(t1, t2)
t1, t2 = "-10h00", "5h00"
check_add(t1, t2)
t1, t2 = "10h00", "-5h00"
check_add(t1, t2)
t1, t2 = "-10h00", "-5h00"
check_add(t1, t2)
t1, t2 = "-10h00", "10h00"
check_add(t1, t2)
t1, t2 = "-10h00", "-5h00"
check_sub(t1, t2)
t1, t2 = "3h30", "10h00"
check_sub(t1, t2)
t1, t2 = "1h00", "2h00"
check_sub(t1, t2)
t1, t2 = "10h00", "5h00"
check_sub(t1, t2)
t1, t2 = "0h30", "1h00"
check_sub(t1, t2)
t1, t2 = "-6h00", "2h00"
check_sub(t1, t2)
t1, t2 = "-1h30", "0h30"
check_add(t1, t2)
# output
10h00 + 5h00 = 15h00
-10h00 + 5h00 = -5h00
10h00 + -5h00 = 5h00
-10h00 + -5h00 = -15h00
-10h00 + 10h00 = 0h00
-10h00 - -5h00 = -5h00
3h30 - 10h00 = -6h30
1h00 - 2h00 = -1h00
10h00 - 5h00 = 5h00
0h30 - 1h00 = -0h30
-6h00 - 2h00 = -8h00
-1h30 + 0h30 = -1h00
Remark: it can be easily extended to days
, weeks
, ... once the input formatting string is standardized. Then modify accordingly the self.str2td
and self.__str_format
methods