从日期时间对象创建64位值

5 投票
1 回答
3824 浏览
提问于 2025-04-18 08:28

我正在从活动目录中提取信息,这意味着我需要处理一些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 个回答

2

我们先来看一下你提到的文档中的一句话:

在活动目录中,时间是以一个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)
>>> ...

撰写回答