将 c# DateTime.Now 转换为二进制

Convert c# DateTime.Now to Binary

我问这个问题是为了学习。

看看我刚刚在wireshark上捕获的这个udp数据包:

(这就是 time.windows.com 为了给我的电脑时间而回复的内容)

无论如何,我的问题是关于突出显示的最后 8 个字节。请注意 Wireshark 如何正确解析日期。 time.windows.com 是如何生成这 8 个字节的?我怎样才能从 DateTime.NowUtc 转到 wireshark 将解析为正确日期的日期?

我试过:

long dateTime = DateTime.Now.ToFileTimeUtc();
var bytes = BitConverter.GetBytes(dateTime);

但是当我发送这 8 个字节时,wireshark 将该日期解析为“4/15/1998 11:27:52 AM”,这是错误的。

自 1970 年以来,我也尝试过添加毫秒数,但仍然显示不正确的日期。

编辑

以下是有关如何解析响应的示例: http://davidnakoko.com/2013/07/c-get-network-time-from-ntp-server/

但是我在哪里可以找到有关如何创建它的示例?

解决方案

感谢@adjan 和@RayFischer 的回答,我想出了一个解决方案。这是:

    public static byte[] ConvertToNtp(DateTime datetime)
    {
        ulong milliseconds = (ulong)((datetime - new DateTime(1900, 1, 1)).TotalMilliseconds);

        ulong intpart = 0, fractpart = 0;
        var ntpData = new byte[8];

        intpart = milliseconds / 1000;
        fractpart = ((milliseconds % 1000) * 0x100000000L) / 1000;

        //Debug.WriteLine("intpart:      " + intpart);
        //Debug.WriteLine("fractpart:    " + fractpart);
        //Debug.WriteLine("milliseconds: " + milliseconds);

        var temp = intpart;
        for (var i = 3; i >= 0; i--)
        {
            ntpData[i] = (byte)(temp % 256);
            temp = temp / 256;
        }

        temp = fractpart;
        for (var i = 7; i >= 4; i--)
        {
            ntpData[i] = (byte)(temp % 256);
            temp = temp / 256;
        }
        return ntpData;
    }

所有操作系统都有两个重要的值: 1) 'epoch' 2) 区间

纪元描述了值所代表的时间间隔。引用 MS 帮助,DateTime.Ticks "represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001"。

但我们不是在看 Windows 时间。我们正在查看 NTP 时间。搜索 "NTP message format" 我发现 RFC958 说 "NTP timestamps are represented as a 64-bit fixed-point number, in seconds relative to 0000 UT on 1 January 1900. The integer part is in the first 32 bits and the fraction part in the last 32 bits"

你如何转换?数学。或者查看此处并进行必要的调整:

根据您链接的代码,您有:

UInt64 milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);

DateTime networkDateTime = (new DateTime(1900, 1, 1)).AddMilliseconds((long)milliseconds);

所以你看到这 8 个字节是自 1/1/1900 以来的毫秒数。因此,要生成这样的时间戳,您可以这样做

ulong milliseconds = (ulong)((DateTime.Now() - new DateTime(1900, 1, 1)).TotalMilliseconds);

.Net 提供了将 DateTime 转换为 64 位二进制表示并返回 DateTime 的方法。

DateTime localDate = new DateTime(2010, 3, 14, 2, 30, 0, DateTimeKind.Local);
long binLocal = localDate.ToBinary();
DateTime localDate2 = DateTime.FromBinary(binLocal);

请参阅 DateTime.ToBinary

上的 MSDN 文档