在将 UNIX 时间戳转换为 .Net DateTime 并返回时保持 date/time 值一致

Keeping date/time values consistent when converting UNIX timestamps to .Net DateTime and back

我需要将 unix TimeStamp 转换为 .Net DateTIme 值,反之亦然。 这没问题,但我需要将转换后的值存储为 Int64(这意味着我丢失了小数位)。

丢失小数位意味着我可以获得原始值和转换值之间的差异。 如果可以的话,我会更改实现并将值存储为 Double 而不是 Int64……但遗憾的是我不能(规范等)。

编辑: 我需要将该值存储为 Int64,表示自 1970 年以来的秒数(unix 时间戳)

我想我已经找到解决这个问题的方法,但我不确定它是否 100% 有效。 (它在我的测试中 100% 有效)。在转换为 int 接缝之前将 Double 值四舍五入以解决问题。

这是否解决了问题?

这是我的代码:

[Test]
public void ConvertTest()
{
    const Int64 orignalUnixValue = 252000596321;
    var referenceTimeZero = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

    //Test 1
    var convertedDateTime = referenceTimeZero.AddSeconds(orignalUnixValue);
    var convertedUnixValue = (convertedDateTime - referenceTimeZero).TotalSeconds;
    var convertedDateTime2 = referenceTimeZero.AddSeconds(convertedUnixValue);

    //This works
    convertedDateTime2.Should()
                      .Be( convertedDateTime );

    //Test 2
    convertedDateTime = referenceTimeZero.AddSeconds(orignalUnixValue);
    var convertedUnixValueCasted = (Int64)(convertedDateTime - referenceTimeZero).TotalSeconds;
    convertedDateTime2 = referenceTimeZero.AddSeconds(convertedUnixValueCasted);

    //Difference of 1 second
    convertedDateTime2.Should()
                      .Be(convertedDateTime);

    //Test 3
    convertedDateTime = referenceTimeZero.AddSeconds(orignalUnixValue);
    convertedUnixValueCasted = (Int64)Math.Ceiling((convertedDateTime - referenceTimeZero).TotalSeconds);
    convertedDateTime2 = referenceTimeZero.AddSeconds(convertedUnixValueCasted);

    //Possible workaround - works for this example
    convertedDateTime2.Should()
                      .Be(convertedDateTime);
}

第一个测试显示了转换值的正确方法,第二个测试显示了当前的实现,第三个包含我的解决方法。

编辑

如果您绝对必须像使用 UNIX 时间戳一样使用这些值,那么我建议使用 Math.Round 而不是 Math.Ceiling。这样您就可以确保数字四舍五入到 最接近的 整数。

不过,正如 Jon 所建议的那样,使用 TimeSpan.Ticks 而不是 TimeSpan.TotalSeconds 更有意义,因为报价开始时是 Int64。这样你就不会出现转换错误了。


说明

您看到的问题似乎是由 double 的存储方式以及将 double 转换为 long 时发生的情况引起的。

我稍微修改了你的代码:

const Int64 orignalUnixValue = 252000596321;
DateTime referenceTimeZero = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

DateTime convertedDateTime = referenceTimeZero.AddSeconds(orignalUnixValue);
double convertedUnixValue = (convertedDateTime - referenceTimeZero).TotalSeconds;

Console.WriteLine(convertedUnixValue); // 252000596321
Console.WriteLine((long)convertedUnixValue); // 252000596320

如您所见,double 变量 似乎 存储了正确的值。但是在转换为 long.

时会出现某种转换错误

通过使用 Jon Skeet 的 DoubleConverter,可以看出变量的值实际上小于 252000596321,这是转换错误的原因。

Console.WriteLine(DoubleConverter.ToExactString(convertedUnixValue));
// 252000596320.999969482421875