簡體   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