繁体   English   中英

如何使用 Python 将二进制日期时间从 SQLServer 转换为人类可读的日期和时间

[英]How to convert binary datetime from SQLServer to human readable date and time with Python

我在原始二进制文件(数据库的一部分)中有一个值,我想转换为人类可以解释的 Python 格式。 这是法医雕刻程序的一部分。 我可以使用这个 SQL 语句转换 8 字节值(您将在 GMT+2 和 GMT 中看到日期)

SELECT CAST(0x0000ae9401039c4a AS datetime), CAST(0x0000ae9400e2a6ca AS datetime)

返回

2022-05-13 15:45:12.780 2022-05-13 13:45:12.780

我尝试使用 DCODE v5.5 ( https://www.digital-detective.net/dcode/ ) 转换二进制值,但找不到任何符合前一个 SQL 语句输出的格式(我已经检查过了就在我要雕刻的数据库中)。

有谁知道如何在 Python 中执行转换?

我想我只需要这个时间表示的起源以及每一点有多少时间。 比较两个恰好相隔 2 小时的时间戳,您可以看到一个我不知道如何解释的“300”。 是不是有点 1/300 秒?

>>> t1=0xae9401039c4a
>>> t2=0xae9400e2a6ca
>>> t1-t2
2160000
>>> (t1-t2)/(2*3600)
300.0

这些是我需要雕刻的数据库的属性: 日期时间属性

精简版

旧的datetime类型将日期存储为从 1900-01-01 开始的 64 位浮点偏移量

floatValue=struct.unpack('<d',bytes)[0]
OLE_TIME_ZERO = datetime.datetime(1900, 01, 01, 0, 0, 0)
date=OLE_TIME_ZERO + datetime.timedelta(days=floatValue)

不过,较新的类型不使用该格式。

openpyxl这样的 Excel 处理库提供了转换 OA/序列日期的函数,比如openpyxl.utils.datetime.from_excel

长解释

SQL Server 中的旧datetime时间类型使用OLE 自动化日期存储格式,该格式也用于 Excel、Visual Basic 和所有支持 OLE/COM 自动化的桌面应用程序,在 1990 年代末和 2000 年代初,在宏病毒之前。 这是一个 64 位浮点数(在 Excel 中称为序列日期) ,其整数部分是自 1899-12-30 以来的偏移量,小数部分是一天中的时间。 除非是 1899-12-31 或 1900-01-01。

早在 Excel 发布时,Lotus 1-2-3 是最流行的电子表格和事实上的标准,并且错误地将 1900 年视为闰年。 为了确保兼容性,Excel 采用了相同的错误。 采用的 VBA 尝试修复错误确保公式产生与 Excel 和 Lotus 相同的结果,因此使用 1899-12-30 作为基础。

SQL Server 团队并不关心这个错误,而是使用了逻辑 1900-01-01。

本质上,这个值是一个timedelta 在 Python 中,您可以将此浮点数转换为 timedelta,方法是将其作为days参数传递给timedelta ,并将其添加到基数 1900-01-01:

OLE_TIME_ZERO = datetime.datetime(1900, 01, 01, 0, 0, 0)
date=OLE_TIME_ZERO + datetime.timedelta(days=floatValue)

要从字节数组中获取 64 位浮点数,您可以使用struct.unpack适当的格式 string 64 位浮点数实际上是双精度数:

floatValue=struct.unpack('<d',bytes)[0]

警告

datetime是一个遗留类型。 2005 年引入的类型datetimedatetime2datetimeoffset具有不同的存储格式。 datetime2datetimeoffset具有可变精度和可变大小。

为了将来参考,我终于能够在这篇文章中找到我需要的数据: https ://www.faqcode4u.com/faq/108331/what-is-the-internal-representation-of-datetime-in-sql- 服务器

此函数将进行转换:

def extr_datetime (bytes):
    days_off = int.from_bytes(bytes[4:8],byteorder='little', signed=True)
    ticks_off = int.from_bytes(bytes[0:4],byteorder='little', signed=True) / 300.0
    epoch = '1900/01/01 00:00:00'
    epoch_obj = datetime.strptime(epoch, '%Y/%m/%d %H:%M:%S')
    d = epoch_obj + timedelta(days=days_off) + timedelta(seconds=ticks_off)
    return d

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM