Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在NTP和C#DateTime之间转换_C#_Ntp - Fatal编程技术网

在NTP和C#DateTime之间转换

在NTP和C#DateTime之间转换,c#,ntp,C#,Ntp,我使用以下代码在NTP和C#DateTime之间进行转换。我认为前躯是正确的,但后躯是错误的 请参阅以下代码以将8个字节转换为DatTime: 将NTP转换为日期时间 以下输入产生输出: bytes = { 131, 170, 126, 128, 46, 197, 205, 234 } var ms = GetMilliSeconds(bytes ); var ntp = ConvertToNtp(ms) //GetMilliSeconds output millise

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

请参阅以下代码以将8个字节转换为DatTime:

将NTP转换为日期时间 以下输入产生输出:

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
请注意,从毫秒到小数部分的转换是错误的。为什么?

更新: 正如乔纳森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];
    }
}
public static void add毫秒(ref byte[]ntpTime,ulong millis)
{
ulong intpart=0,fractpart=0;
对于(变量i=0;i<4;i++)
intpart=256*intpart+ntpTime[i];
对于(变量i=4;i=4)
ntpTime[i]=新分形零件[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);
}
是0.7毫秒把事情搞砸了

由于NTP时间戳包含32位小数秒(),因此转换为整数毫秒将导致精度损失

对最新情况的答复: 将毫秒添加到NTP时间戳并不像添加整数部分和小数部分那么简单。考虑将小数1.75和2.75相加。0.75+0.75=1.5,你需要把这个带到整数部分。此外,NTP时间戳中的分数部分不是base-10,因此不能只添加毫秒。一些转换是必要的,使用类似于
ms/1000=ntpfrac/0x100000000
的比例

这是完全未经测试的,但我认为您应该将
intpart+=
fracpart+=
中的
addmillizes
行替换为更像这样:

intpart += millis / 1000;

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

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

日期时间标记为NTP并返回

static long ntpEpoch = (new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).Ticks;
static public long Ntp2Ticks(UInt64 a)
{
  var b = (decimal)a * 1e7m / (1UL << 32);
  return (long)b + ntpEpoch;
}
static public UInt64 Ticks2Ntp(long a)
{
    decimal b = a - ntpEpoch;
    b = (decimal)b / 1e7m * (1UL << 32);
    return (UInt64)b;
}
static long ntpEpoch=(新的DateTime(1900,1,1,0,0,0,0,DateTimeKind.Utc)).Ticks;
静态公共长Ntp2Ticks(UInt64 a)
{

var b=(十进制)a*1e7m/(1UL对Cameron解决方案的建议: 使用


确保您的本地时间计算结果与其他时间相同,但没有除法

 return (ulong)(elapsedTime.Ticks * 1e-7 * 4294967296ul)


这很有道理,谢谢。现在,与其来回转换,不如直接用NTP进行操作。我更新了我的问题以反映这一点。我更新了下面的答案。祝你好运!朱利叶斯,试试你提供的DateTime.UtcNow.Ticks的第一个表达式,告诉我会发生什么。修复它,我会重新启动投票失败。卡梅隆请解释一下……你会使用Utc。现在,减去所需的历元以获得elapsedTime……从那里得到的答案是一样的。你想看完整的方法吗?朱利叶斯,我的错误,我没有减去历元。请编辑你的答案,这样我就可以把投票结果还给你。朱利叶斯,我相信有代码中仍然存在一个错误,您选择在1e-7中使用浮点表示51位尾数,而不是64位精度,这意味着您正在丢失信息和数字的尾端。参见示例:Julius,您可以使用此小提琴查看需要多少位来存储(现在是历元)delta:,55位,double无法精确存储。另一个提琴显示double/decimal之间的计算是如何不同的。请记住,2036年后,答案中包含的历元将溢出,因此RFC中已给出另一个历元,并且应包含在此答案中,以及检测使用哪个历元的逻辑。如果您在回购协议中计算NTP时间的代码是错误的,请查看此提琴以了解原因:
intpart += millis / 1000;

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

intpart += fractsum / 0x100000000L;
fractpart = fractsum % 0x100000000L;
static long ntpEpoch = (new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).Ticks;
static public long Ntp2Ticks(UInt64 a)
{
  var b = (decimal)a * 1e7m / (1UL << 32);
  return (long)b + ntpEpoch;
}
static public UInt64 Ticks2Ntp(long a)
{
    decimal b = a - ntpEpoch;
    b = (decimal)b / 1e7m * (1UL << 32);
    return (UInt64)b;
}
ntpEpoch = (new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).Ticks;
 return (ulong)(elapsedTime.Ticks * 1e-7 * 4294967296ul)
 return (ulong)(((long)(elapsedTime.Ticks * 0.0000001) << 32) + (elapsedTime.TotalMilliseconds % 1000 * 4294967296 * 0.001));


        //TicksPerPicosecond = 0.0000001m

        //4294967296 = uint.MaxValue + 1

        //0.001 == PicosecondsPerNanosecond
public static System.DateTime UtcEpoch2036 = new System.DateTime(2036, 2, 7, 6, 28, 16, System.DateTimeKind.Utc);

public static System.DateTime UtcEpoch1900 = new System.DateTime(1900, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);

 public static ulong DateTimeToNptTimestamp(ref System.DateTime value/*, bool randomize = false*/)
    {
        System.DateTime baseDate = value >= UtcEpoch2036 ? UtcEpoch2036 : UtcEpoch1900;

        System.TimeSpan elapsedTime = value > baseDate ? value.ToUniversalTime() - baseDate.ToUniversalTime() : baseDate.ToUniversalTime() - value.ToUniversalTime();

        //Media.Common.Extensions.TimeSpan.TimeSpanExtensions.MicrosecondsPerMillisecond = 1000

        //TicksPerPicosecond = 0.0000001m = 1e-7

        //4294967296 = uint.MaxValue + 1

        //0.001 == PicosecondsPerNanosecond = 1e-3            

        //429496.7296 Picoseconds = 4.294967296e-7 Seconds

        //4.294967296e-7 * 1000 Milliseconds per second = 0.0004294967296 * 1e+9 (PicosecondsPerMilisecond) = 429.4967296

        //0.4294967296 nanoseconds * 100 nanoseconds = 1 tick = 42.94967296 * 10000 ticks per millisecond = 429496.7296 / 1000 = 429.49672960000004

        unchecked
        {
            //return (ulong)((long)(elapsedTime.Ticks * 0.0000001m) << 32 | (long)((decimal)elapsedTime.TotalMilliseconds % 1000 * 4294967296m * 0.001m));
            //return (ulong)(((long)(elapsedTime.Ticks * 0.0000001m) << 32) + (elapsedTime.TotalMilliseconds % 1000 * 4294967296ul * 0.001));
            //return (ulong)(elapsedTime.Ticks * 1e-7 * 4294967296ul); //ie-7 * 4294967296ul = 429.4967296 has random diff which complies better? (In order to minimize bias and help make timestamps unpredictable to an intruder, the non - significant bits should be set to an unbiased random bit string.)
            //return (ulong)(elapsedTime.Ticks * 429.4967296m);//decimal precision is better but we still lose precision because of the magnitude? 0.001 msec dif ((ulong)(elapsedTime.Ticks * 429.4967296000000000429m))
            //429.49672960000004m has reliable 003 msec diff
            //Has 0 diff but causes fraction to be different from examples...
            //return (ulong)((elapsedTime.Ticks + 1) * 429.4967296m);
            //Also adding + 429ul;
            return (ulong)(elapsedTime.Ticks * 429.496729600000000000429m);
            //var ticks =  (ulong)(elapsedTime.Ticks * 429.496729600000000000429m); //Has 0 diff on .137 measures otherwise 0.001 msec or 1 tick, keeps the examples the same.
            //if(randomize) ticks ^= (ulong)(Utility.Random.Next() & byte.MaxValue);
            //return ticks;
        }
public static System.DateTime NptTimestampToDateTime(ref uint seconds, ref uint fractions, System.DateTime? epoch = null)
        {
            //Convert to ticks
            //ulong ticks = (ulong)((seconds * System.TimeSpan.TicksPerSecond) + ((fractions * System.TimeSpan.TicksPerSecond) / 0x100000000L)); //uint.MaxValue + 1

            unchecked
            {
                //Convert to ticks,                 

                //'UtcEpoch1900.AddTicks(seconds * System.TimeSpan.TicksPerSecond + ((long)(fractions * 1e+12))).Millisecond' threw an exception of type 'System.ArgumentOutOfRangeException'

                //0.01 millisecond = 1e+7 picseconds = 10000 nanoseconds
                //10000 nanoseconds = 10 micros = 10000000 pioseconds
                //0.001 Centisecond = 10 Microsecond
                //1 Tick = 0.1 Microsecond
                //0.1 * 100 Nanos Per Tick = 100
                //TenMicrosecondsPerPicosecond = 10000000 = TimeSpan.TicksPerSecond = 10000000 
                                                                                            //System.TimeSpan.TicksPerSecond is fine here also...
                long ticks = seconds * System.TimeSpan.TicksPerSecond + ((long)(fractions * Media.Common.Extensions.TimeSpan.TimeSpanExtensions.TenMicrosecondsPerPicosecond) >> Common.Binary.BitsPerInteger);

                //Return the result of adding the ticks to the epoch
                //If the epoch was given then use that value otherwise determine the epoch based on the highest bit.
                return epoch.HasValue ? epoch.Value.AddTicks(ticks) :
                        (seconds & 0x80000000L) == 0 ?
                            UtcEpoch2036.AddTicks(ticks) :
                                UtcEpoch1900.AddTicks(ticks);
            }
        }