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。
在 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。