Java 与 C# Long 到 DateTime 的转换

Java Vs C# Long to DateTime Conversion

在 Java 中,我有以下通过的测试

// 42 bits of time is good enough for the next 100 years.
// An IEEE double has 52 bits of mantissa, so our dates can be easily fit.
@Test
public void testMaxBits() throws ParseException {
    // Maximum 42 bit integer
    long millis = (1L << 42) - 1;
    Date date = new Date(millis);
    //DateTime maxDate = new DateTime(2109, 5, 15, 8, 35, 11, 103);
    Date maxDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").parse("2109-05-15T08:35:11.103");
    Assert.assertEquals(maxDate, date);
}

现在,我想在 C# 中做同样的事情,所以我在 LinqPAD 中进行了测试,测试 C# 实现的正确性

DateTime maxDate = new DateTime(2109, 5, 15, 8, 35, 11, 103);
long beginTicks = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
long l = (1L << 42) - 1;
DateTime date = new DateTime(beginTicks + l, DateTimeKind.Utc);
maxDate.Dump();
date.Dump();

输出不匹配,输出的值ToString()值为

maxDate = 15/05/2109 08:35:11 date = 06/01/1970 02:10:04

我在这里错过了什么?


编辑。我在下面看到@zmitrok 的一个很好的答案,我已经改变了

DateTime date = new DateTime(beginTicks + l, DateTimeKind.Utc);

DateTime date = new DateTime(beginTicks + 
    l * TimeSpan.TicksPerMillisecond, DateTimeKind.Utc);

但现在得到

date = 15/05/2109 07:35:11

时间都去哪儿了?

我想你需要用这个常数乘以刻度:https://msdn.microsoft.com/en-us/library/system.timespan.tickspermillisecond%28v=vs.110%29.aspx

您正在使用的 constructor 将滴答作为第一个参数,但是您传递的是一个添加到毫秒的值。

Ticks: A date and time expressed in the number of 100-nanosecond intervals that have elapsed since January 1, 0001 at 00:00:00.000 in the Gregorian calendar.

您的测试基本上混淆了滴答与毫秒。如果您只需要存储自 unix 纪元以来的毫秒数,那么就这样做 - 但我建议使用类似这样的方法来执行转换:

public static readonly DateTime UnixEpoch
    = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

public DateTime FromMillisecondsSinceUnixEpoch(long milliseconds)
{
     return UnixEpoch.AddMilliseconds(milliseconds);
}

(作为旁注,that method already exists in my Noda Time 项目...提示提示 :)

你的测试将是:

[TestMethod]
public void TestMaxBits()
{
    long maxMillis = (1L << 42) - 1;
    DateTime maxDate = DateTimeHelper.FromMillisecondsSinceUnixEpoch(maxMillis);
    Assert.Greater(maxDate, new DateTime(2100, 1, 1, 0, 0, 0));
}

注意:

  • 此代码根本没有提及报价,因为您对报价不感兴趣
  • 此代码不会断言最大日期是某个非常具体的值,因为那不是您关心的;你关心的是 42 位的时间会载你到本世纪末。 ("next 100 years" 评论有些似是而非,因为距离现在不到 100 年 2109,所以我假设它真的意味着 "until the end of the 21st century.")

这当然让你的问题 "Where has the hour gone?" 无关紧要 - 但答案很简单 SimpleDateFormat 默认使用系统时区,所以你实际上依赖于时区您正在 运行 测试的系统,这是一个 真的 坏主意。如果你把SimpleDateFormat的时区设置为UTC,你会发现Java也是07:35:11。