| Total Complexity | 42 |
| Total Lines | 141 |
| Duplicated Lines | 85.11 % |
| Changes | 0 | ||
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like dynamicserialize.dstypes.com.raytheon.uf.common.time.TimeRange often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # |
||
| 2 | # SOFTWARE HISTORY |
||
| 3 | # |
||
| 4 | # Date Ticket# Engineer Description |
||
| 5 | # ------------ ---------- ----------- -------------------------- |
||
| 6 | # ??/??/?? xxxxxxxx Initial Creation. |
||
| 7 | # 01/22/14 2667 bclement fixed millisecond support |
||
| 8 | # 02/28/14 2667 bclement constructor can take extra micros for start and end |
||
| 9 | # 06/24/15 4480 dgilling fix __eq__. |
||
| 10 | # |
||
| 11 | # |
||
| 12 | |||
| 13 | import calendar |
||
| 14 | import datetime |
||
| 15 | import time |
||
| 16 | |||
| 17 | MAX_TIME = 2147483647 |
||
| 18 | MICROS_IN_SECOND = 1000000 |
||
| 19 | |||
| 20 | |||
| 21 | View Code Duplication | class TimeRange(object): |
|
|
|
|||
| 22 | def __init__(self, start=None, end=None, startExtraMicros=None, endExtraMicros=None): |
||
| 23 | self.start = self.__convertToDateTimeWithExtra(start, startExtraMicros) |
||
| 24 | self.end = self.__convertToDateTimeWithExtra(end, endExtraMicros) |
||
| 25 | |||
| 26 | def __str__(self): |
||
| 27 | return self.__repr__() |
||
| 28 | |||
| 29 | def __repr__(self): |
||
| 30 | return "(" + self.start.strftime("%b %d %y %H:%M:%S %Z") + ", " + \ |
||
| 31 | self.end.strftime("%b %d %y %H:%M:%S %Z") + ")" |
||
| 32 | |||
| 33 | def __eq__(self, other): |
||
| 34 | if not isinstance(self, type(other)): |
||
| 35 | return False |
||
| 36 | |||
| 37 | if self.isValid() and other.isValid(): |
||
| 38 | return self.getStart() == other.getStart() and self.getEnd() == other.getEnd() |
||
| 39 | elif not self.isValid() and not other.isValid(): |
||
| 40 | return True |
||
| 41 | else: |
||
| 42 | return False |
||
| 43 | |||
| 44 | def __ne__(self, other): |
||
| 45 | return not self.__eq__(other) |
||
| 46 | |||
| 47 | def __convertToDateTimeWithExtra(self, timeArg, extraMicros): |
||
| 48 | rval = self.__convertToDateTime(timeArg) |
||
| 49 | if rval is not None and extraMicros is not None: |
||
| 50 | rval = rval + datetime.timedelta(microseconds=extraMicros) |
||
| 51 | return rval |
||
| 52 | |||
| 53 | def __convertToDateTime(self, timeArg): |
||
| 54 | if timeArg is None: |
||
| 55 | return None |
||
| 56 | if isinstance(timeArg, datetime.datetime): |
||
| 57 | return timeArg |
||
| 58 | elif isinstance(timeArg, time.struct_time): |
||
| 59 | return datetime.datetime(*timeArg[:6]) |
||
| 60 | elif isinstance(timeArg, float): |
||
| 61 | # seconds as float, should be avoided due to floating point errors |
||
| 62 | totalSecs = int(timeArg) |
||
| 63 | micros = int((timeArg - totalSecs) * MICROS_IN_SECOND) |
||
| 64 | return self.__convertSecsAndMicros(totalSecs, micros) |
||
| 65 | elif isinstance(timeArg, int): |
||
| 66 | # seconds as integer |
||
| 67 | totalSecs = timeArg |
||
| 68 | return self.__convertSecsAndMicros(totalSecs, 0) |
||
| 69 | else: |
||
| 70 | return None |
||
| 71 | |||
| 72 | def __convertSecsAndMicros(self, seconds, micros): |
||
| 73 | if seconds < MAX_TIME: |
||
| 74 | rval = datetime.datetime.utcfromtimestamp(seconds) |
||
| 75 | else: |
||
| 76 | extraTime = datetime.timedelta(seconds=(seconds - MAX_TIME)) |
||
| 77 | rval = datetime.datetime.utcfromtimestamp(MAX_TIME) + extraTime |
||
| 78 | return rval.replace(microsecond=micros) |
||
| 79 | |||
| 80 | def getStart(self): |
||
| 81 | return self.start.utctimetuple() |
||
| 82 | |||
| 83 | def getStartInMillis(self): |
||
| 84 | return self._getInMillis(self.start) |
||
| 85 | |||
| 86 | def setStart(self, start, extraMicros=None): |
||
| 87 | self.start = self.__convertToDateTimeWithExtra(start, extraMicros) |
||
| 88 | |||
| 89 | def getEnd(self): |
||
| 90 | return self.end.utctimetuple() |
||
| 91 | |||
| 92 | def getEndInMillis(self): |
||
| 93 | return self._getInMillis(self.end) |
||
| 94 | |||
| 95 | def _getInMillis(self, time): |
||
| 96 | rval = int(calendar.timegm(time.utctimetuple()) * 1000) |
||
| 97 | rval += time.microsecond // 1000 |
||
| 98 | return rval |
||
| 99 | |||
| 100 | def setEnd(self, end, extraMicros=None): |
||
| 101 | self.end = self.__convertToDateTimeWithExtra(end, extraMicros) |
||
| 102 | |||
| 103 | def duration(self): |
||
| 104 | delta = self.end - self.start |
||
| 105 | return int(delta.total_seconds()) |
||
| 106 | |||
| 107 | def contains(self, timeArg): |
||
| 108 | if isinstance(timeArg, TimeRange): |
||
| 109 | if self.duration() == 0: |
||
| 110 | return self.__eq__(timeArg) |
||
| 111 | elif timeArg.duration() == 0: |
||
| 112 | return self.contains(timeArg.start) |
||
| 113 | return timeArg.start >= self.start and timeArg.end <= self.end |
||
| 114 | else: |
||
| 115 | convTime = self.__convertToDateTime(timeArg) |
||
| 116 | if not isinstance(convTime, datetime.datetime): |
||
| 117 | raise TypeError("Invalid type for argument time specified to TimeRange.contains().") |
||
| 118 | if self.duration() != 0: |
||
| 119 | return self.start <= convTime < self.end |
||
| 120 | return convTime == self.start |
||
| 121 | |||
| 122 | def isValid(self): |
||
| 123 | return bool(self.start != self.end) |
||
| 124 | |||
| 125 | def overlaps(self, timeRange): |
||
| 126 | return timeRange.contains(self.start) or self.contains(timeRange.start) |
||
| 127 | |||
| 128 | def combineWith(self, timeRange): |
||
| 129 | if self.isValid() and timeRange.isValid(): |
||
| 130 | newStart = min(self.start, timeRange.start) |
||
| 131 | newEnd = max(self.end, timeRange.end) |
||
| 132 | return TimeRange(newStart, newEnd) |
||
| 133 | elif self.isValid(): |
||
| 134 | return self |
||
| 135 | |||
| 136 | return timeRange |
||
| 137 | |||
| 138 | @staticmethod |
||
| 139 | def allTimes(): |
||
| 140 | return TimeRange(0, MAX_TIME) |
||
| 141 |