首页 > 解决方案 > 如何将 [Log Content 0] 中 fn_dblog() 详细信息中的 8 字节日期时间转换为 C# DateTime 对象?

问题描述

我删除了最近插入的一行数据。我没有恢复和前滚这个巨大数据库的第二个副本来检索插入的数据,而是尝试使用 fn_dblog()“未记录”系统函数来检索它。使用描述(可在此处找到:https ://sqlfascination.com/2010/02/03/how-do-you-decode-a-simple-entry-in-the-transaction-log-part-1/ )

在 [Log Content 0] 列 fn_dblog() 返回的内容中,我成功地从日志文件中检索了我插入的(以及后来删除的)数据。在为固定宽度列数据保留的二进制数据部分中,我发现 SQL DateTime 列值占用 8 个字节。我正在.NET 程序中处理二进制数据,使用适用于 Int 或 BigInt 值的 BitConverter.ToInt64 或 BitConverter.ToInt32

我已经设法检索了我需要的所有插入的列值,除了日期时间列......

我不清楚如何将 SQL DateTime 列的 8 个字节解释为 C# DateTime 对象。如果有帮助,下面是从特定日期时间的事务日志数据中检索到的日期时间 8 字节的示例十六进制和 Int64 版本。

二进制日期时间(2020 年 7 月 31 日左右):0xF030660009AC0000(字节序反转:0x0000AC09006630F0)

作为 Int64:189154661380804

有什么建议么?这是日期的内部 SQL Server 表示,我不确定在哪里可以找到文档...

标签: sql-serverdatetimesql-server-2008-r2transaction-logtransactionloganalysis

解决方案


我终于找到了答案:存储为 VARBINARY 的 SQL DateTime(类似于我从事务日志中读取的字节)包含两个整数。第一个是日期部分 - 自 1900 年 1 月 1 日以来的天数。对于较早的日期,它将是负面的。

第二个整数是自午夜以来的毫秒数,除以 3.33333333。

因为字节存储为 long 和反向,缓冲区中 8 个字节的前 4 个字节是分钟,第二个是日期。

所以这是我用来获取日期的代码片段。我一次运行一个固定长度字段,跟踪字节数组中的当前偏移量......变量 ba 是 [Log Content 0] 列中字节的字节数组。

        int TimeInt;
        int DateInt;
        DateTime tmpDt;

        //initialize the starting point for datetime - 1/1/1900
        tmpDt = new DateTime(1900, 1, 1);
        // get the time portion of the SQL DateTime
        TimeInt = BitConverter.ToInt32(ba, currOffset);
        currOffset += 4;
        // get the date portion of the SQL DateTime
        DateInt = BitConverter.ToInt32(ba, currOffset);
        currOffset += 4;
        // Add the number of days since 1/1/1900
        tmpDt = tmpDt.AddDays(DateInt);
        // Add the number of milliseconds since midnight
        tmpDt = tmpDt.AddMilliseconds(TimeInt * 3.3333333);
        

推荐阅读