2011-05-12 74 views
4

将一些计算例程从.Net移植到Java,但Date类似乎存在一些精度问题。也许我已经睁大眼睛盯着这个,但我不知道为什么结果会有所不同。DateTime精度差异.NET vs Java

我应该如何处理日期以获得跨平台的相同数字(毫秒)?

[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); 
} 

的Java

@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(); 
} 
+0

你是说格式不同,或者它们返回不同的值?如果它们返回不同的值,那可能是因为它们相距几毫秒? – soandos 2011-05-12 16:57:48

+0

也不要在java中使用java日期,请使用joda日期:) – bwawok 2011-05-12 17:06:02

+0

是否为.NET完成了Noda时间?我知道有人正在研究Joda时间的.NET端口... – David 2011-05-12 17:21:47

回答

8

太棒了!

问题:

Java Calendar months start at 0.Net Datetime months start at 1

所以你正在比较.Net二月到Java游行。而且,正如阿尔扬所建议的,3月27日是许多时区夏时制的改变。

这是使用Java日历时非常常见的问题。为避免它,你应该使用这样的命名常量:

Date d1 = createDate(2011, Calendar.MARCH, 26, 19, 25, 24); // Calendar.MARCH == 2 
+0

确实似乎是这个问题。在这几个月中使用0 - 11可能很容易导致错误,就像这里的情况一样。它也欺骗了我。 – Arjan 2011-05-12 17:45:34

0

你确定问题出在日期时间结构,而不是在双层结构?从documentation on the .NET Double data type

浮点值和 损精

记住,浮点数只能近似于十进制 号码和一个 浮点数的精度决定如何准确地确定该数字接近 十进制数字。默认情况下,双精度 值包含精度为 的15个十进制数字,尽管最多可在内部维护17位 数字。该 精度浮点数 有几个后果:

既然你不返回小数毫秒,你可以使用System.Int64(长在C#)的数据类型。您的值在该数据类型的允许范围内。 Int64(long)的max value是9,223,372,036,854,775,807

-1

它来自您正在扣除的方式。在Java中,你减去2个表示时间的long。如果您从长期回到日期进行转换,它可能不是您最初设置的日期,因为小数点会有一些损失。在.net中,您正在减去实际日期,然后转换为毫秒。所以这个结果实际上会更精确。如果您将.net中的时间转换为总毫秒,那么减去我会打赌你会发现更接近的结果。

+0

有人在乎解释倒票吗? – Chad 2011-05-12 18:36:29

1

以毫秒为单位的差值为3,600,000,因此恰好为1小时。难道一种语言使用的时区设置不同于其他时区设置,即DST有变化吗?

我已经做了一些更多的测试。 PHP结果与C#结果相匹配(只有秒而不是毫秒),而且我的Java结果与您的Java结果相匹配。这个问题似乎是Java中的时区处理中的一个错误。根据Java第二次是在DST,这是不正确的在我的时区(欧洲/阿姆斯特丹)。

0

我很困惑。你是说第二个(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(); 
} 
+0

你在什么时区? – Arjan 2011-05-12 17:35:31

+0

@Arjan:JodaTime的DateTimeZone.getDefault()。toString()是我的系统上的“America/Los_Angeles”。 – ccoakley 2011-05-12 17:57:18

+0

这解释了为什么你没有这个问题。夏令时并非在3月27日开始,因此所有计算均正确完成。如果您想重现该问题,请尝试从指定日期减去14(因此将26更改为12,将28更改为14)。 – Arjan 2011-05-12 18:44:41