gpt4 book ai didi

c# - 在 NTP 和 C# DateTime 之间转换

转载 作者:太空狗 更新时间:2023-10-29 21:13:23 24 4
gpt4 key购买 nike

我使用以下代码在 NTP 和 C# DateTime 之间进行转换。我认为前向翻转是正确的,向后翻转是错误的。

看下面的代码将8个字节转换成一个DatTime:

将 NTP 转换为日期时间

public static ulong GetMilliSeconds(byte[] ntpTime)
{
ulong intpart = 0, fractpart = 0;

for (var i = 0; i <= 3; i++)
intpart = 256 * intpart + ntpTime[i];
for (var i = 4; i <= 7; i++)
fractpart = 256 * fractpart + ntpTime[i];

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

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

public static DateTime ConvertToDateTime(byte[] ntpTime)
{
var span = TimeSpan.FromMilliseconds(GetMilliSeconds(ntpTime));
var time = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
time += span;
return time;
}

将 DateTime 转换为 NTP

public static byte[] ConvertToNtp(ulong milliseconds)
{
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;
}

以下输入产生输出:

bytes = { 131, 170, 126, 128,
46, 197, 205, 234 }

var ms = GetMilliSeconds(bytes );
var ntp = ConvertToNtp(ms)

//GetMilliSeconds output
milliseconds: 2208988800182
intpart: 2208988800
fractpart: 784715242

//ConvertToNtp output
milliseconds: 2208988800182
intpart: 2208988800
fractpart: 781684047

注意从毫秒到小数部分的转换是错误的。为什么?

更新:

正如 Jonathan S. 指出的那样 - 这是分数的损失。因此,我不想来回转换,而是想直接使用 NTP 时间戳进行操作。更具体地说,加上毫秒。我假设以下函数可以做到这一点,但我很难验证它。我对小数部分非常不确定。

public static void AddMilliSeconds(ref byte[] ntpTime, ulong millis)
{
ulong intpart = 0, fractpart = 0;

for (var i = 0; i < 4; i++)
intpart = 256 * intpart + ntpTime[i];
for (var i = 4; i <= 7; i++)
fractpart = 256 * fractpart + ntpTime[i];

intpart += millis / 1000;
fractpart += millis % 1000;

var newIntpart = BitConverter.GetBytes(SwapEndianness(intpart));
var newFractpart = BitConverter.GetBytes(SwapEndianness(fractpart));

for (var i = 0; i < 8; i++)
{
if (i < 4)
ntpTime[i] = newIntpart[i];
if (i >= 4)
ntpTime[i] = newFractpart[i - 4];
}
}

最佳答案

您在这里遇到的是从 NTP 时间戳到毫秒的转换精度丢失。当您从 NTP 转换为毫秒时,您将丢弃部分分数。然后,当您获取该值并尝试转换回来时,您会得到一个略有不同的值。如果将 ulong 值更改为 decimal 值,您可以更清楚地看到这一点,如本测试所示:

public static decimal GetMilliSeconds(byte[] ntpTime)
{
decimal intpart = 0, fractpart = 0;

for (var i = 0; i <= 3; i++)
intpart = 256 * intpart + ntpTime[i];
for (var i = 4; i <= 7; i++)
fractpart = 256 * fractpart + ntpTime[i];

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

Console.WriteLine("milliseconds: " + milliseconds);
Console.WriteLine("intpart: " + intpart);
Console.WriteLine("fractpart: " + fractpart);
return milliseconds;
}

public static byte[] ConvertToNtp(decimal milliseconds)
{
decimal intpart = 0, fractpart = 0;
var ntpData = new byte[8];

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

Console.WriteLine("milliseconds: " + milliseconds);
Console.WriteLine("intpart: " + intpart);
Console.WriteLine("fractpart: " + fractpart);

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;
}

public static void Main(string[] args)
{
byte[] bytes = { 131, 170, 126, 128,
46, 197, 205, 234 };

var ms = GetMilliSeconds(bytes);
Console.WriteLine();
var ntp = ConvertToNtp(ms);
}

这会产生以下结果:

milliseconds: 2208988800182.7057548798620701
intpart: 2208988800
fractpart: 784715242

milliseconds: 2208988800182.7057548798620701
intpart: 2208988800.1827057548798620701
fractpart: 784715242.0000000000703594496

是这 ~0.7 毫秒把事情搞砸了。

由于 NTP 时间戳包括 32 位小数秒 ( "a theoretical resolution of 2^-32 seconds or 233 picoseconds" ),转换为整数毫秒将导致精度损失。

响应更新:

将毫秒添加到 NTP 时间戳并不像添加整数部分和小数部分那么简单。考虑将小数点 1.75 和 2.75 相加。 0.75 + 0.75 = 1.5,您需要将 1 带入整数部分。此外,NTP 时间戳中的小数部分不是以 10 为底,因此您不能只添加毫秒。需要进行一些转换,使用类似 ms/1000 = ntpfrac/0x100000000 的比例。

这完全未经测试,但我认为您想要替换 AddMilliSeconds 中的 intpart +=fracpart += 行> 更像这样:

intpart += millis / 1000;

ulong fractsum = fractpart + (millis % 1000) / 1000 * 0x100000000L);

intpart += fractsum / 0x100000000L;
fractpart = fractsum % 0x100000000L;

关于c# - 在 NTP 和 C# DateTime 之间转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16763300/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com