Python OLE2日期格式转换

时间:2009-11-30 03:57:53

标签: python ole

我创建了一个python脚本,它从Word文档中的OLE流中提取数据,但是在将OLE2格式的时间戳转换为更易于阅读的内容时遇到了问题:(

抽出的时间戳是12760233021,但我不能在我的生活中将其转换为2007年3月12日或类似的日期。

非常感谢任何帮助。

编辑: 好的我已经在我的一个word文档上运行了脚本,该文档是在 31/10 / 2009,10:05:00 上创建的。 OLE DocumentSummaryInformation流中的创建日期为 12901417500

另一个例子是在27/10/2009,15:33:00创建的word doc,在OLE DocumentSummaryInformation流中给出创建日期12901091580。

有关这些OLE流属性的MSDN文档是http://msdn.microsoft.com/en-us/library/aa380376%28VS.85%29.aspx

将这些流拉出的def如下:

import OleFileIO_PL as ole

def enumerateStreams(item):
    # item is an arbitrary file
    if ole.isOleFile('%s' % item):
        loader = ole.OleFileIO('%s' % item)
        # enumerate all the OLE streams in the office file
        streams = loader.listdir()
        streamProps = []
        for stream in streams:
            if stream[0] == '\x05SummaryInformation':
                # get all the properties fro the SummaryInformation OLE stream
                streamProps.append(loader.getproperties(stream))
            elif stream[0] == '\x05DocumentSummaryInformation':
                # get all the properties from the DocumentSummaryInformation stream
                streamProps.append(loader.getproperties(stream))
     return streamProps

2 个答案:

答案 0 :(得分:2)

(0)请澄清“像2007年3月12日或类似”:你的意思是你希望11位数字转换为2007年3月12日,或者是“2007年3月12日”仅仅是为了表达其中的格式你想显示日期吗?如果是后者,你不能通过用MS Word或OpenOffice.org的文字处理小工具检查一些文件来提供预期的结果吗?您打算如何验证提供的任何解决方案是否真的有效?

(1)请提供多个(OLE,预期)对,以便更加可靠地验证任何建议的解决方案的正确操作。如果可能,您是否可以创建具有已知预期值的示例,例如2000年1月1日,2001年1月1日,2001年1月2日,2001年2月2日?

(2)从“从OLE流中提取数据”来看,无论是想要在OLE2复合文档标题中创建文件等时间戳,还是想要在内容中存在时间戳,都是不明显的。请说明你在哪里搜寻时间戳。如果您能够提供与您感兴趣的时间戳相关的MS文档,那么它也会有很大的帮助......当然它必须告诉您格式是什么,即使它间接地由一个或两个内部/外部-document hops。

(3)请说明你是如何把它拉出来的 - 这是一根绳子吗?固定11个字节?或者它是str(你从64位字段转换的某个int)?转换怎么样?除了说明外,还要显示转换代码。不要从内存中重新键入代码;使用复制/粘贴。

请通过编辑问题提供所需信息,而不是评论。

等待信息时更新:

OLE复合文档标题中的文件创建和修改时间戳似乎是64位小端整数(自1601-01-01T00:00:00以来的秒数)* 10 ** 7。

在OLE2数据中的数据中使用的DATE类型似乎是自1899-12-30T00:00:00以来的64位小端IEEE 754浮点数(天及其一小部分)。是的,那天是30,而不是31。

检查提供的2个示例后更新:

两个观察时间戳(将在当地时间)之间的差异为325920秒:

>>> import datetime
>>> t0 = datetime.datetime(2009,10,27,15,33,0)
>>> t1 = datetime.datetime(2009,10,31,10,5,0)
>>> t1-t0
datetime.timedelta(3, 66720)
>>> secs = 3 * 24 * 60 * 60 + 66720
>>> secs
325920

这与两个幻数之间的差异相同:

>>> 12901417500 - 1290191580
325920

因此神奇的数字代表了自某个时代以来的秒数......

>>> m1 = 12901417500
>>> days, seconds = divmod(m1, 60*60*24)
>>> epoch = t1 - datetime.timedelta(days, seconds)
>>> epoch
datetime.datetime(1601, 1, 1, 11, 0)

因此,幻数代表自1601-01-01T00:00:00Z以来的秒数,而您的TZ距离UTC仅11小时。

这两个魔术数字不适合32位...看起来像(a)它自1601年起以64位存储(浪费大约29位!)或(b)存储为(正如预期的那样,自1601年以来,100纳秒单位的数量),但在看到它之前,有一些东西除以10 ** 7。

您提供的文档参考仅表示它是VF_FILETIME (UTC)类型。谷歌搜索,我发现有几条关于调用Windows函数来操纵时间戳的MS线索,但就我看来没有定义。然而,有两个第三方笔记(来自perlmonks和Apache POI项目)说了很多相同的事情:“”这看起来像一个Windows VT_FILETIME数据类型,它是一个64位无符号整数,表示已经过去的数量自1601年1月1日起100纳秒“”“

从犯罪现场更新:

似乎您正在使用OleFileIO_PL来读取文件。通过唯一的源文件快速搜索显示:

    elif type == VT_FILETIME:
        value = long(i32(s, offset+4)) + (long(i32(s, offset+8))<<32)
        # FIXME: this is a 64-bit int: "number of 100ns periods
        # since Jan 1,1601".  Should map this to Python time
        value = value / 10000000L # seconds

答案 1 :(得分:2)

这个问题很老但仍然有用。我最近改进了OleFileIO_PL,通过将日期自动转换为Python日期时间来解决问题。

请参阅此页面上的文档,尤其是有关get_metadata和get_properties的部分: https://bitbucket.org/decalage/olefileio_pl

使用get_metadata时,标准属性流中的所有时间戳(例如'\ x05SummaryInformation')都将转换为Python日期时间。 如果您需要使用get_properties,请使用convert_time选项:

p = ole.getproperties('specialprops', convert_time=True)

菲利普。