我将一些计算例程从.Net移植到Java,但是Date类中似乎存在一些精度问题。也许我对此视而不见,但我无法弄清楚为什么结果不同。
我应该如何处理日期以跨平台获得相同的数字(毫秒)?
。网
[Test] public void foo() {
DateTime dt1 = new DateTime(2011, 2, 26, 19, 25, 24);
DateTime dt2 = new DateTime(2011, 2, 28, 18, 40, 25);
double millis = (dt2 - dt1).TotalMilliseconds;
Assert.AreEqual(170101000, millis);
}
爪哇岛
@Test public void foo() throws Exception {
Date d1 = createDate(2011, 2, 26, 19, 25, 24);
Date d2 = createDate(2011, 2, 28, 18, 40, 25);
long millis = d2.getTime() - d1.getTime();
Assert.assertEquals(166501000, millis, 0.01);
}
private static Date createDate(int year, int month, int day,
int hour, int minute, int second) {
Calendar instance = Calendar.getInstance();
instance.clear();
instance.set(year, month, day, hour, minute, second);
return instance.getTime();
}
太好了!
问题:
Java 日历月份从 0 开始,.Net 日期时间月份从 1 开始。
所以你正在比较.Net二月和Java三月。而且,正如 Arjan 所建议的那样,3 月 27 日是许多时区夏令时的变化。
这是使用 Java 日历时非常常见的问题。为了避免这种情况,您应该像这样对月份使用命名常量:
Date d1 = createDate(2011, Calendar.MARCH, 26, 19, 25, 24); // Calendar.MARCH == 2
以毫秒为单位的差异是 3,600,000,所以正好是 1 小时。可能是一种语言使用的时区设置与另一种语言不同,其中 DST 有变化?
我做了更多的测试。PHP 结果与 C# 结果匹配(只有我得到秒而不是毫秒),我的 Java 结果与您的 Java 结果匹配。问题似乎是 Java 中时区处理中的错误。根据Java的说法,第二次是DST,这在我的时区(欧洲/阿姆斯特丹)是不正确的。
您确定问题出在 DateTime 结构中而不是在 Double 结构中吗? 来自有关 .NET Double 数据类型的文档:
浮点值和损失 精度
请记住,浮点数只能近似于小数 数字,并且精度为 浮点数确定如何 准确地说,这个数字近似于 十进制数。默认情况下,双精度 值包含 15 个十进制数字 精度,尽管最大为 17 数字在内部维护。这 浮点数的精度 有几个后果:
由于不返回小数毫秒,因此可以使用 System.Int64(在 c# 中为 long)数据类型。 您的值在该数据类型的允许范围内。 Int64(长整型)的最大值为 9,223,372,036,854,775,807
我很困惑。你是说第二个(Java)测试通过吗?因为我实际上得到的数字与第一个 (C#) 测试相同:170101000。
这是我的测试(通过)。我加入了JodaTime对象作为日期和日历的替代品:
@Test public void foo() throws Exception {
DateTime dt1 = new DateTime(2011, 2, 26, 19, 25, 24, 0);
DateTime dt2 = new DateTime(2011, 2, 28, 18, 40, 25, 0);
Duration d = new Duration(dt1, dt2);
Assert.assertEquals(170101000, d.getMillis(), 0.01);
Date d1 = createDate(2011, 2, 26, 19, 25, 24);
Date d2 = createDate(2011, 2, 28, 18, 40, 25);
long millis = d2.getTime() - d1.getTime();
Assert.assertEquals(170101000, millis, 0.01);
}
private static Date createDate(int year, int month, int day,
int hour, int minute, int second) {
Calendar instance = Calendar.getInstance();
instance.clear();
instance.set(year, month, day, hour, minute, second);
return instance.getTime();
}
它来自你减法的方式。 在 java 中,您减去 2 个表示时间的长整型。 如果您从长回日期进行转换,则可能不是您最初设置的转换,因为小数点后位会有一些损失。 在 .net 中,您将减去实际日期,然后转换为毫秒。 所以这个结果实际上会更精确。 如果您将 .net 中的时间转换为总毫秒,那么减去我敢打赌您会发现更接近的结果。