Issue #2667 fixed microseconds floating point error

time ranges now take any extra microseconds as separate argument


Former-commit-id: 24d9440e440b74f6b1b907062b10da0fef268aed
This commit is contained in:
Brian Clements 2014-02-28 15:46:17 -06:00
parent 45e8290111
commit fdf3e42cb7
2 changed files with 41 additions and 17 deletions

View file

@ -29,6 +29,7 @@
# ------------ ---------- ----------- --------------------------
# 09/16/10 dgilling Initial Creation.
# 01/22/14 2667 bclement use method to get millis from time range
# 02/28/14 2667 bclement deserialize now converts millis to micros
#
#
#
@ -39,6 +40,8 @@ from dynamicserialize.dstypes.com.raytheon.uf.common.time import TimeRange
ClassAdapter = 'com.raytheon.uf.common.time.TimeRange'
MICROS_IN_MILLISECOND = 1000
MILLIS_IN_SECOND = 1000
def serialize(context, timeRange):
context.writeI64(timeRange.getStartInMillis())
@ -49,8 +52,12 @@ def deserialize(context):
endTime = context.readI64()
timeRange = TimeRange()
timeRange.setStart(startTime/1000.0)
timeRange.setEnd(endTime/1000.0)
# java uses milliseconds, python uses microseconds
startSeconds = startTime // MILLIS_IN_SECOND
endSeconds = endTime // MILLIS_IN_SECOND
startExtraMicros = (startTime % MILLIS_IN_SECOND) * MICROS_IN_MILLISECOND
endExtraMicros = (endTime % MILLIS_IN_SECOND) * MICROS_IN_MILLISECOND
timeRange.setStart(startSeconds, startExtraMicros)
timeRange.setEnd(endSeconds, endExtraMicros)
return timeRange

View file

@ -27,6 +27,7 @@
# ------------ ---------- ----------- --------------------------
# ??/??/?? xxxxxxxx Initial Creation.
# 01/22/14 2667 bclement fixed millisecond support
# 02/28/14 2667 bclement constructor can take extra micros for start and end
#
#
#
@ -39,9 +40,9 @@ MAX_TIME = 2147483647
MICROS_IN_SECOND = 1000000
class TimeRange(object):
def __init__(self, start=None, end=None):
self.start = self.__convertToDateTime(start)
self.end = self.__convertToDateTime(end)
def __init__(self, start=None, end=None, startExtraMicros=None, endExtraMicros=None):
self.start = self.__convertToDateTimeWithExtra(start, startExtraMicros)
self.end = self.__convertToDateTimeWithExtra(end, endExtraMicros)
def __str__(self):
return self.__repr__()
@ -55,6 +56,12 @@ class TimeRange(object):
def __ne__(self, other):
return (not self.__eq__(other))
def __convertToDateTimeWithExtra(self, timeArg, extraMicros):
rval = self.__convertToDateTime(timeArg)
if rval is not None and extraMicros is not None:
rval = rval + datetime.timedelta(microseconds=extraMicros)
return rval
def __convertToDateTime(self, timeArg):
if timeArg is None:
return None
@ -62,13 +69,23 @@ class TimeRange(object):
return timeArg
elif isinstance(timeArg, time.struct_time):
return datetime.datetime(*timeArg[:6])
else:
elif isinstance(timeArg, float):
# seconds as float, should be avoided due to floating point errors
totalSecs = long(timeArg)
micros = int((timeArg - totalSecs) * MICROS_IN_SECOND)
if totalSecs < MAX_TIME:
rval = datetime.datetime.utcfromtimestamp(totalSecs)
return self.__convertSecsAndMicros(totalSecs, micros)
elif isinstance(timeArg, (int, long)):
# seconds as integer
totalSecs = timeArg
return self.__convertSecsAndMicros(totalSecs, 0)
else:
extraTime = datetime.timedelta(seconds=(totalSecs - MAX_TIME))
return None
def __convertSecsAndMicros(self, seconds, micros):
if seconds < MAX_TIME:
rval = datetime.datetime.utcfromtimestamp(seconds)
else:
extraTime = datetime.timedelta(seconds=(seconds - MAX_TIME))
rval = datetime.datetime.utcfromtimestamp(MAX_TIME) + extraTime
return rval.replace(microsecond=micros)
@ -78,8 +95,8 @@ class TimeRange(object):
def getStartInMillis(self):
return self._getInMillis(self.start)
def setStart(self, start):
self.start = self.__convertToDateTime(start)
def setStart(self, start, extraMicros=None):
self.start = self.__convertToDateTimeWithExtra(start, extraMicros)
def getEnd(self):
return self.end.utctimetuple()
@ -92,8 +109,8 @@ class TimeRange(object):
rval += time.microsecond // 1000
return rval
def setEnd(self, end):
self.end = self.__convertToDateTime(end)
def setEnd(self, end, extraMicros=None):
self.end = self.__convertToDateTimeWithExtra(end, extraMicros)
def duration(self):
delta = self.end - self.start