DataTime.__init__()   F
last analyzed

Complexity

Conditions 17

Size

Total Lines 76
Code Lines 51

Duplication

Lines 76
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 51
dl 76
loc 76
rs 1.8
c 0
b 0
f 0
cc 17
nop 4

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like dynamicserialize.dstypes.com.raytheon.uf.common.time.DataTime.DataTime.__init__() 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
#    05/28/13         2023         dgilling       Implement __str__().
8
#    01/22/14         2667         bclement       preserved milliseconds in string representation
9
#    03/03/14         2673         bsteffen       allow construction using a Date for refTime
10
#    06/24/14         3096         mnash          implement __cmp__
11
#    06/24/15         4480         dgilling       implement __hash__ and __eq__,
12
#                                                 replace __cmp__ with rich comparison
13
#                                                 operators.
14
#    05/26/16         2416         rjpeter        Added str based constructor.
15
#    08/02/16         2416         tgurney        Forecast time regex bug fix,
16
#                                                 plus misc cleanup
17
#
18
19
import calendar
20
import datetime
21
import re
22
import time
23
import numpy
24
from six.moves import cStringIO as StringIO
25
26
from dynamicserialize.dstypes.java.util import Date
27
from dynamicserialize.dstypes.java.util import EnumSet
28
29
from .TimeRange import TimeRange
30
31
_DATE = r'(\d{4}-\d{2}-\d{2})'
32
_TIME = r'(\d{2}:\d{2}:\d{2})'
33
_MILLIS = '(?:\.(\d{1,3})(?:\d{1,4})?)?'  # might have microsecond but that is thrown out
34
REFTIME_PATTERN_STR = _DATE + '[ _]' + _TIME + _MILLIS
35
FORECAST_PATTERN_STR = r'(?:[ _]\((\d+)(?::(\d{1,2}))?\))?'
36
VALID_PERIOD_PATTERN_STR = r'(?:\[' + REFTIME_PATTERN_STR + '--' + REFTIME_PATTERN_STR + r'\])?'
37
STR_PATTERN = re.compile(REFTIME_PATTERN_STR + FORECAST_PATTERN_STR + VALID_PERIOD_PATTERN_STR)
38
39
40 View Code Duplication
class DataTime(object):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
41
42
    def __init__(self, refTime=None, fcstTime=None, validPeriod=None):
43
        """
44
        Construct a new DataTime.
45
        May also be called as DataTime(str) to parse a string and create a
46
        DataTime from it. Some examples of valid DataTime strings:
47
48
             '2016-08-02 01:23:45.0'
49
             '2016-08-02 01:23:45.123'
50
             '2016-08-02 01:23:45.0 (17)',
51
             '2016-08-02 01:23:45.0 (17:34)'
52
             '2016-08-02 01:23:45.0[2016-08-02_02:34:45.0--2016-08-02_03:45:56.0]'
53
             '2016-08-02 01:23:45.456_(17:34)[2016-08-02_02:34:45.0--2016-08-02_03:45:56.0]'
54
        """
55
        if fcstTime is not None:
56
            self.fcstTime = int(fcstTime)
57
        else:
58
            self.fcstTime = 0
59
        self.refTime = refTime
60
        if validPeriod is not None and not isinstance(validPeriod, TimeRange):
61
            raise ValueError("Invalid validPeriod object specified for DataTime.")
62
        self.validPeriod = validPeriod
63
        self.utilityFlags = EnumSet('com.raytheon.uf.common.time.DataTime$FLAG')
64
        self.levelValue = numpy.float64(-1.0)
65
66
        if self.refTime is not None:
67
            if isinstance(self.refTime, datetime.datetime):
68
                self.refTime = int(calendar.timegm(self.refTime.utctimetuple()) * 1000)
69
            elif isinstance(self.refTime, time.struct_time):
70
                self.refTime = int(calendar.timegm(self.refTime) * 1000)
71
            elif hasattr(self.refTime, 'getTime'):
72
                # getTime should be returning ms, there is no way to check this
73
                # This is expected for java Date
74
                self.refTime = int(self.refTime.getTime())
75
            else:
76
                try:
77
                    self.refTime = int(self.refTime)
78
                except ValueError:
79
                    # Assume first arg is a string. Attempt to parse.
80
                    match = STR_PATTERN.match(self.refTime)
81
                    if match is None:
82
                        raise ValueError('Could not parse DataTime info from '
83
                                         + str(refTime))
84
85
                    groups = match.groups()
86
                    rMillis = groups[2] or 0
87
                    fcstTimeHr = groups[3]
88
                    fcstTimeMin = groups[4]
89
                    periodStart = groups[5], groups[6], (groups[7] or 0)
90
                    periodEnd = groups[8], groups[9], (groups[10] or 0)
91
                    self.refTime = self._getTimeAsEpochMillis(groups[0], groups[1], rMillis)
92
93
                    if fcstTimeHr is not None:
94
                        self.fcstTime = int(fcstTimeHr) * 3600
95
                        if fcstTimeMin is not None:
96
                            self.fcstTime += int(fcstTimeMin) * 60
97
98
                    if periodStart[0] is not None:
99
                        self.validPeriod = TimeRange()
100
                        periodStartTime = self._getTimeAsEpochMillis(*periodStart)
101
                        self.validPeriod.setStart(periodStartTime / 1000)
102
                        periodEndTime = self._getTimeAsEpochMillis(*periodEnd)
103
                        self.validPeriod.setEnd(periodEndTime / 1000)
104
105
            self.refTime = Date(self.refTime)
106
107
            if self.validPeriod is None:
108
                validTimeMillis = self.refTime.getTime() + int(self.fcstTime * 1000)
109
                self.validPeriod = TimeRange()
110
                self.validPeriod.setStart(validTimeMillis / 1000)
111
                self.validPeriod.setEnd(validTimeMillis / 1000)
112
113
        # figure out utility flags
114
        if self.fcstTime:
115
            self.utilityFlags.add("FCST_USED")
116
        if self.validPeriod and self.validPeriod.isValid():
117
            self.utilityFlags.add("PERIOD_USED")
118
119
    def getRefTime(self):
120
        return self.refTime
121
122
    def setRefTime(self, refTime):
123
        self.refTime = refTime
124
125
    def getFcstTime(self):
126
        return self.fcstTime
127
128
    def setFcstTime(self, fcstTime):
129
        self.fcstTime = fcstTime
130
131
    def getValidPeriod(self):
132
        return self.validPeriod
133
134
    def setValidPeriod(self, validPeriod):
135
        self.validPeriod = validPeriod
136
137
    def getUtilityFlags(self):
138
        return self.utilityFlags
139
140
    def setUtilityFlags(self, utilityFlags):
141
        self.utilityFlags = utilityFlags
142
143
    def getLevelValue(self):
144
        return self.levelValue
145
146
    def setLevelValue(self, levelValue):
147
        self.levelValue = numpy.float64(levelValue)
148
149
    def __str__(self):
150
        sbuffer = StringIO()
151
152
        if self.refTime is not None:
153
            refTimeInSecs = self.refTime.getTime() / 1000
154
            micros = (self.refTime.getTime() % 1000) * 1000
155
            dtObj = datetime.datetime.utcfromtimestamp(refTimeInSecs)
156
            dtObj = dtObj.replace(microsecond=micros)
157
            # This won't be compatible with java or string from java since its to microsecond
158
            sbuffer.write(dtObj.isoformat(' '))
159
160
        if "FCST_USED" in self.utilityFlags:
161
            hrs = int(self.fcstTime / 3600)
162
            mins = int((self.fcstTime - (hrs * 3600)) / 60)
163
            sbuffer.write(" (" + str(hrs))
164
            if mins != 0:
165
                sbuffer.write(":" + str(mins))
166
            sbuffer.write(")")
167
168
        if "PERIOD_USED" in self.utilityFlags:
169
            sbuffer.write("[")
170
            sbuffer.write(self.validPeriod.start.isoformat(' '))
171
            sbuffer.write("--")
172
            sbuffer.write(self.validPeriod.end.isoformat(' '))
173
            sbuffer.write("]")
174
175
        strVal = sbuffer.getvalue()
176
        sbuffer.close()
177
        return strVal
178
179
    def __repr__(self):
180
        return "<DataTime instance: " + str(self) + " >"
181
182
    def __hash__(self):
183
        hashCode = hash(self.refTime) ^ hash(self.fcstTime)
184
        if self.validPeriod is not None and self.validPeriod.isValid():
185
            hashCode ^= hash(self.validPeriod.getStart())
186
            hashCode ^= hash(self.validPeriod.getEnd())
187
        hashCode ^= hash(self.levelValue)
188
        return hashCode
189
190
    def __eq__(self, other):
191
        if not isinstance(self, type(other)):
192
            return False
193
194
        if other.getRefTime() is None:
195
            return self.fcstTime == other.fcstTime
196
197
        dataTime1 = (self.refTime, self.fcstTime, self.validPeriod, self.levelValue)
198
        dataTime2 = (other.refTime, other.fcstTime, other.validPeriod, other.levelValue)
199
        return dataTime1 == dataTime2
200
201
    def __ne__(self, other):
202
        return not self.__eq__(other)
203
204
    def __lt__(self, other):
205
        if not isinstance(self, type(other)):
206
            return NotImplemented
207
208
        myValidTime = self.getRefTime().getTime() + self.getFcstTime()
209
        otherValidTime = other.getRefTime().getTime() + other.getFcstTime()
210
        if myValidTime < otherValidTime:
211
            return True
212
213
        if self.fcstTime < other.fcstTime:
214
            return True
215
216
        if self.levelValue < other.levelValue:
217
            return True
218
219
        myValidPeriod = self.validPeriod
220
        otherValidPeriod = other.validPeriod
221
        if myValidPeriod != otherValidPeriod:
222
            if myValidPeriod.duration() < otherValidPeriod.duration():
223
                return True
224
            return myValidPeriod.getStartInMillis() < otherValidPeriod.getStartInMillis()
225
        return False
226
227
    def __le__(self, other):
228
        if not isinstance(self, type(other)):
229
            return NotImplemented
230
231
        return self.__lt__(other) or self.__eq__(other)
232
233
    def __gt__(self, other):
234
        if not isinstance(self, type(other)):
235
            return NotImplemented
236
237
        myValidTime = self.getRefTime().getTime() + self.getFcstTime()
238
        otherValidTime = other.getRefTime().getTime() + other.getFcstTime()
239
        if myValidTime > otherValidTime:
240
            return True
241
242
        if self.fcstTime > other.fcstTime:
243
            return True
244
245
        if self.levelValue > other.levelValue:
246
            return True
247
248
        myValidPeriod = self.validPeriod
249
        otherValidPeriod = other.validPeriod
250
        if myValidPeriod != otherValidPeriod:
251
            if myValidPeriod.duration() > otherValidPeriod.duration():
252
                return True
253
            return myValidPeriod.getStartInMillis() > otherValidPeriod.getStartInMillis()
254
        return False
255
256
    def __ge__(self, other):
257
        if not isinstance(self, type(other)):
258
            return NotImplemented
259
260
        return self.__gt__(other) or self.__eq__(other)
261
262
    def _getTimeAsEpochMillis(self, dateStr, timeStr, millis):
263
        t = time.strptime(dateStr + ' ' + timeStr, '%Y-%m-%d %H:%M:%S')
264
        epochSeconds = calendar.timegm(t)
265
        return int(epochSeconds * 1000) + int(millis)
266