Source code for dk.ttcal.duration

# -*- coding: utf-8 -*-
"""Extension of datetime.timedelta.
"""
import datetime
import re


[docs]class Duration(datetime.timedelta): """A duration of time. """ @classmethod
[docs] def sum(cls, sequence, start=None): """Return the sum of sequence. (built-in sum only works with numbers). """ if start is None: start = cls(0) res = start for item in sequence: res += item return res
@classmethod
[docs] def parse(cls, txt): """Parse a textual representation into a Duration object. Format HHH:MM:SS. """ if not txt: return None time_matcher = re.compile(r""" (?: (?P<negation>-) )? (?: (?P<weeks>\d+) \W* (?:weeks?|w),? )? \W* (?: (?P<days>\d+) \W* (?:days?|d),? )? \W* (?: (?P<hours>\d+): (?P<minutes>\d+) (?::(?P<seconds>\d+) (?:\.(?P<microseconds>\d+))?)? )? """, re.VERBOSE) time_matches = time_matcher.match(txt) time_groups = time_matches.groupdict() keys = time_groups.keys() if time_groups.get('negation') == '-': scale = -1 keys.remove('negation') else: scale = 1 for key in keys: time_groups[key] = int(time_groups[key]) if time_groups[key] else 0 time_groups["days"] = time_groups["days"] + (time_groups["weeks"] * 7) res = cls( days=time_groups["days"], hours=time_groups["hours"], minutes=time_groups["minutes"], seconds=time_groups["seconds"]) return res * scale
def __new__(cls, *args, **kw): if len(args) == 1 and isinstance(args[0], datetime.timedelta): years = 0 days = args[0].days hours = 0 minutes = 0 seconds = args[0].seconds else: years = kw.get('years', 0) days = kw.get('days', 0) hours = kw.get('hours', 0) minutes = kw.get('minutes', 0) seconds = kw.get('seconds', 0) # an average year is 365.2425 days.. leap_days = int(365.2425 * years - 365 * years) obj = super(Duration, cls).__new__(cls, days=days + years * 365, hours=hours + leap_days, minutes=minutes, seconds=seconds) return obj def __repr__(self): dt = self.duration_tuple() return '%sDuration(hours=%d, minutes=%d, seconds=%d)' % dt
[docs] def duration_tuple(self): """Return self as hours, minutes, seconds. """ seconds = self.toint() sign = -1 if seconds < 0 else 1 seconds *= sign minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) return '-' if sign < 0 else '', hours, minutes, seconds
@property def hrs(self): """The number of hours in self. """ sgn, hr, _mn, _sc = self.duration_tuple() return int(sgn == "") * hr @property def mins(self): """The number of minutes in self. """ sgn, _hr, mn, _sc = self.duration_tuple() return int(sgn == "") * mn @property def secs(self): """The number of seconds in self. """ sgn, _hr, _mn, sc = self.duration_tuple() return int(sgn == "") * sc def __str__(self): return '%s%d:%02d:%02d' % self.duration_tuple() def __unicode__(self): return unicode(str(self))
[docs] def toint(self): """Convert self to integer. """ return self.seconds + 3600 * 24 * self.days
__hash__ = datetime.timedelta.__hash__ def __eq__(self, other): if hasattr(other, '__req__'): return other.__req__(self) if isinstance(other, datetime.timedelta): return super(Duration, self).__eq__(other) # if isinstance(other, Duration): # return self.duration_tuple() == other.duration_tuple() if isinstance(other, int) and other == 0: return self.toint() == 0 return False def __ne__(self, other): if hasattr(other, '__rne__'): return other.__rne__(self) if isinstance(other, datetime.timedelta): return super(Duration, self).__ne__(other) # if isinstance(other, Duration): # return self.duration_tuple() != other.duration_tuple() if isinstance(other, int) and other == 0: return self.toint() != 0 return False def __lt__(self, other): if hasattr(other, '__rlt__'): return other.__rlt__(self) if isinstance(other, datetime.timedelta): return super(Duration, self).__lt__(other) if hasattr(other, 'toint'): return self.toint() < other.toint() return False def __le__(self, other): if hasattr(other, '__rle__'): return other.__rle__(self) if isinstance(other, datetime.timedelta): return super(Duration, self).__le__(other) if hasattr(other, 'toint'): return self.toint() <= other.toint() return False def __gt__(self, other): if hasattr(other, '__rgt__'): return other.__rgt__(self) if isinstance(other, datetime.timedelta): return super(Duration, self).__gt__(other) if isinstance(other, int): return self.toint() > other if hasattr(other, 'toint'): return self.toint() > other.toint() return False def __ge__(self, other): if hasattr(other, '__rge__'): return other.__rge__(self) if isinstance(other, datetime.timedelta): return super(Duration, self).__ge__(other) if hasattr(other, 'toint'): return self.toint() >= other.toint() return False def __mul__(self, other): return Duration(super(Duration, self).__mul__(other)) def __add__(self, other): return Duration(super(Duration, self).__add__(other)) def __sub__(self, other): return Duration(super(Duration, self).__sub__(other)) def __div__(self, other): if isinstance(other, Duration): try: return float(self.toint()) / float(other.toint()) except ZeroDivisionError: return 0.0 return Duration(super(Duration, self).__div__(other))
# def __truediv__(self, other): # # if isinstance(other, Duration): # # try: # # return int(float(self.toint()) / float(other.toint())) # # except ZeroDivisionError: # # return 0 # return Duration(super(Duration, self).__truediv__(other)) # def __rsub__(self, other): # return other.__sub__(self) # # def __rmul__(self, other): # return other.__mul__(self) # # def __rfloordiv__(self, other): # return other.__floordiv__(self) # # def __rdiv__(self, other): # return other.__div__(self) # # def __radd__(self, other): # return other.__add__(self)