Commit a243da5f authored by Alexander Korolkov's avatar Alexander Korolkov

Fix conversion from FILETIME to datetime

Previously, datetime.utcfromtimestamp() was used,
which is limited to 1970-2038 range on 32-bit POSIX systems.
Adding timedelta to datetime(1601, 1, 1) works better.
parent 56f45306
......@@ -23,6 +23,7 @@ UaTypes = ("Boolean", "SByte", "Byte", "Int8", "UInt8", "Int16", "UInt16", "Int3
EPOCH_AS_FILETIME = 116444736000000000 # January 1, 1970 as MS file time
HUNDREDS_OF_NANOSECONDS = 10000000
FILETIME_EPOCH_AS_DATETIME = datetime(1601, 1, 1)
class UTC(tzinfo):
......@@ -39,7 +40,7 @@ class UTC(tzinfo):
return timedelta(0)
# methods copied from David Buxton <david@gasmark6.com> sample code
# method copied from David Buxton <david@gasmark6.com> sample code
def datetime_to_win_epoch(dt):
if (dt.tzinfo is None) or (dt.tzinfo.utcoffset(dt) is None):
dt = dt.replace(tzinfo=UTC())
......@@ -48,14 +49,7 @@ def datetime_to_win_epoch(dt):
def win_epoch_to_datetime(epch):
(s, ns100) = divmod(epch - EPOCH_AS_FILETIME, HUNDREDS_OF_NANOSECONDS)
try:
dt = datetime.utcfromtimestamp(s)
except Exception as ex: #FIXME: find out what kind of exceptin is raised!!!
logger.debug("Exception occurred during conversion within 'win_epoch_to_datetime'. %s", ex)
return datetime.now()
dt = dt.replace(microsecond=(ns100 // 10))
return dt
return FILETIME_EPOCH_AS_DATETIME + timedelta(microseconds=epch // 10)
def uatype_to_fmt(uatype):
......
......@@ -152,11 +152,22 @@ class Unit(unittest.TestCase):
dt = ua.win_epoch_to_datetime(epch)
self.assertEqual(now, dt)
# python's datetime has a range from Jan 1, 0001 to the end of year 9999
# windows' filetime has a range from Jan 1, 1601 to approx. year 30828
# let's test an overlapping range [Jan 1, 1601 - Dec 31, 9999]
dt = datetime(1601, 1, 1)
self.assertEqual(ua.win_epoch_to_datetime(ua.datetime_to_win_epoch(dt)), dt)
dt = datetime(9999, 12, 31, 23, 59, 59)
self.assertEqual(ua.win_epoch_to_datetime(ua.datetime_to_win_epoch(dt)), dt)
epch = 128930364000001000
dt = ua.win_epoch_to_datetime(epch)
epch2 = ua.datetime_to_win_epoch(dt)
self.assertEqual(epch, epch2)
epch = 0
self.assertEqual(ua.datetime_to_win_epoch(ua.win_epoch_to_datetime(epch)), epch)
def test_equal_nodeid(self):
nid1 = ua.NodeId(999, 2)
nid2 = ua.NodeId(999, 2)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment