我正在从Active Directory中提取信息,这意味着我正在处理一些COMObjects。其中一个日期存储为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)
现在有了这个,我想为此建立一个单元测试。但是,我似乎无法弄清楚如何从datetime对象生成64位整数。我目前正在做的是我创建了一个复制COMObject的类,它将其值存储为两个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位值?
旁注:我意识到我可能已经过度思考了一些,因为我的单元测试确实通过但是我宁愿没有硬编码值,因此测试更强大而且不依赖于值那“只是工作”。
答案 0 :(得分:2)
我们将从您链接到的文档中引用:
活动目录中的时间存储在保留的64位整数中 跟踪已经过的100纳秒间隔的数量 自1601年1月1日起。
因此,将这些部分视为两个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 timestamp,这是一个浮点数(在本例中),包含自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)
>>> ...