从日期时间对象创建64位值
我正在从活动目录中提取信息,这意味着我需要处理一些COM对象。其中一个对象有一个日期,它是以64位整数的形式存储的(实际上是两个32位整数)。我已经找到了将其转换为日期时间对象的方法,使用了以下代码。
def convert_to_datetime(time_object):
# http://docs.activestate.com/activepython/2.6/pywin32/html/com/help/active_directory.html
d = 116444736000000000L #diference between 1601 and 1970
time_int = (((long(time_object.highpart) << 32) + long(time_object.lowpart)) - d)/10000000
return datetime.datetime.fromtimestamp(time_int)
现在有了这个,我想为这个功能写一个单元测试。不过,我现在遇到的问题是,我不知道如何从日期时间对象生成一个64位整数。目前,我创建了一个类来模拟COM对象,它将值存储为两个32位整数,然后我手动写了与日期和整数匹配的值。但是,我希望能有一种方法,根据“现在”的时间来生成这些值。
这是我目前的单元测试,看起来是可以通过的。
def test_convert_to_datetime_for_64bit_int_returns_value(self):
now_com_time = COMObjectDate(30375774,216380170)
self.assertEqual(datetime.datetime(2014, 6, 3, 14, 0, 13), AD_AG.convert_to_datetime(now_com_time))
class COMObjectDate:
def __init__(self, high, low):
self.highpart = high
self.lowpart = low
有没有办法从日期时间对象生成这两个32位值呢?
附注:我意识到我可能有点想太多了,因为我的单元测试确实通过了,但我更希望不要使用硬编码的值,这样测试会更强大,而不是依赖于那些“刚好能用”的值。
1 个回答
我们先来看一下你提到的文档中的一句话:
在活动目录中,时间是以一个64位的整数来存储的,这个整数记录了自1601年1月1日以来经过的100纳秒的时间间隔。
可以把这个64位整数分成两个32位的整数(高位和低位,前面补零):
bin(30375774) =
00000001110011110111111101011110
bin(216380170) =
00001100111001011011001100001010
把这两个部分(“高位”和“低位”)合在一起,就得到了这个64位的整数:
0000000111001111011111110101111000001100111001011011001100001010
换算成十进制,就是 130462956137067274
。
要计算自1601年1月1日以来经过的秒数,我们需要把这个数字除以 10000000
。
130462956137067274 / 10000000
= 13.046.295.613 seconds since the 1st of january 1601
如果你想反向操作,得到对应的32位整数部分,可以简单地进行日期计算:从自1601年1月1日以来的秒数开始,乘以10000000,然后把64位整数分成两个32位的部分(这可以通过位移操作轻松完成)。
convert_to_datetime
方法的实现也应该很清楚。你需要知道的是,datetime.fromtimestamp()
方法需要一个POSIX时间戳,这是一个浮点数(在这个情况下),表示自epoch
(1970年1月1日)以来经过的秒数。这就解释了方法体中基于偏移量的计算。
====> 1. Creating a Unix timestamp (seconds since epoch) from a datetime
>>> import time
>>> import datetime
>>> time.mktime(datetime.datetime.now().timetuple())
1401828155.0
====> 2. Adding the difference in seconds between 01/01/1601 and 01/01/1970
====> (11644473600 seconds)
>>> 11644473600 + 1401828155
13046301755
====> 3. Multiply by 10000000
>>> 13046301755 * 10000000
130463017550000000
====> 4. Interpret as binary. Add leading zero's until you have 64 bits.
>>> bin(130463017550000000)
'0b111001111011111110110110001011001011001001010111110000000'
====> 5. Split the high part (32 bits) and the low part (32 bits)
>>> ...