dynamicserialize.dstypes.com.raytheon.uf.common.time.TimeRange   A
last analyzed

Complexity

Total Complexity 42

Size/Duplication

Total Lines 141
Duplicated Lines 85.11 %

Importance

Changes 0
Metric Value
wmc 42
eloc 98
dl 120
loc 141
rs 9.0399
c 0
b 0
f 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A TimeRange.getEndInMillis() 2 2 1
B TimeRange.__convertToDateTime() 18 18 6
A TimeRange.getStart() 2 2 1
A TimeRange.__ne__() 2 2 1
A TimeRange.__str__() 2 2 1
A TimeRange.duration() 3 3 1
A TimeRange.getEnd() 2 2 1
B TimeRange.__eq__() 10 10 6
A TimeRange.__convertToDateTimeWithExtra() 5 5 3
A TimeRange.isValid() 2 2 1
A TimeRange.setEnd() 2 2 1
A TimeRange.overlaps() 2 2 1
A TimeRange.__convertSecsAndMicros() 7 7 2
A TimeRange.getStartInMillis() 2 2 1
A TimeRange.setStart() 2 2 1
B TimeRange.contains() 14 14 6
A TimeRange.allTimes() 3 3 1
A TimeRange.__init__() 3 3 1
A TimeRange.__repr__() 3 3 1
A TimeRange._getInMillis() 4 4 1
A TimeRange.combineWith() 9 9 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

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:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
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