[英]How to convert combination of binary and ascii to human readable format in python
[英]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 年引入的类型date
、 time
、 datetime2
和datetimeoffset
具有不同的存储格式。 datetime2
和datetimeoffset
具有可变精度和可变大小。
为了将来参考,我终于能够在这篇文章中找到我需要的数据: https ://www.faqcode4u.com/faq/108331/what-is-the-internal-representation-of-datetime-in-sql- 服务器
- https://www.faqcode4u.com/faq/108331/what-is-the-internal-representation-of-datetime-in-sql-server
- 这些细节据说是不透明的,但我在网上找到的大多数资源 (1)、(2) 如下所示:
- 前 4 个字节存储自 SQL Server 纪元(1900 年 1 月 1 日)以来的天数,并且
- 第二个 4 字节存储午夜后的滴答数,其中“滴答”为 3.3 毫秒。
- 前四个字节是有符号的(可以是正数或负数),这解释了为什么可以表示比纪元更早的日期。
- https://docs.microsoft.com/en-us/sql/t-sql/functions/date-and-time-data-types-and-functions-transact-sql?redirectedfrom=MSDN&view=sql-server-ver16
- 范围:1753-01-01 到 9999-12-31
- 精度:0.00333 秒
此函数将进行转换:
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.