Разница точности DateTime. NET против Java - PullRequest
4 голосов
/ 12 мая 2011

Я портирую некоторые процедуры вычислений из .Net в Java, но в классах Date, похоже, есть некоторые проблемы с точностью.Может быть, я не видел этого, но не могу понять, почему результаты отличаются.

Как мне обращаться с датами, чтобы получить одинаковые числа (миллисекунды) на разных платформах?

.Net

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

Ответы [ 5 ]

8 голосов
/ 12 мая 2011

Замечательно!

Проблема:

Месяцы Java Calendar начинаются с 0 и .Net Datetime месяцы начинаются с 1 .

Итак, вы сравниваете .Net февраль с маршем Java.И, как предположил Арджан, 27 марта произойдет переход на летнее время во многих часовых поясах.

Это очень распространенная проблема при использовании Java Calendar.Чтобы избежать этого, вы должны использовать именованные константы для таких месяцев:

Date d1 = createDate(2011, Calendar.MARCH, 26, 19, 25, 24); // Calendar.MARCH == 2
1 голос
/ 12 мая 2011

Разница в миллисекундах составляет 3 600 000, то есть ровно 1 час. Может ли быть так, что один язык использует настройку часового пояса, отличную от другой, где происходит изменение с или на летнее время?

Я провел еще несколько испытаний. Результат PHP совпадает с результатом C # (только я получаю секунды вместо миллисекунд), а мой результат Java соответствует вашему результату Java. Кажется, проблема в ошибке обработки часовых поясов в Java. Согласно Java, второй раз в DST, что не правильно в моем часовом поясе (Европа / Амстердам).

0 голосов
/ 12 мая 2011

Я в замешательстве.Вы говорите, что второй (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 голосов
/ 12 мая 2011

Это происходит от того, как вы вычитаете.В Java вы вычитаете 2 длинных, которые представляют времена.Если вы выполняете преобразование из длинного спина в дату, это может быть не тем, что вы установили изначально, поскольку есть некоторая потеря в десятичном знаке.В .net вы вычитаете фактические даты, а затем переводите в миллисекунды.Так что этот результат на самом деле будет более точным.Если вы конвертируете время в .net в общее количество миллисекунд, то вычтите, что держу пари, что вы найдете гораздо более близкие результаты.

0 голосов
/ 12 мая 2011

Вы уверены, что проблема в структуре DateTime, а не в структуре Double?Из документации для типа данных .NET Double :

Значения с плавающей запятой и Потеря точности

Помните, что число с плавающей запятой может быть только приблизительнымдесятичное число и то, что точность числа с плавающей запятой определяет, насколько точно это число приближается к десятичному числу.По умолчанию значение Double содержит 15 десятичных цифр точности, хотя внутренне поддерживается максимум 17 цифр.Точность числа с плавающей запятой имеет несколько последствий:

Поскольку вы не возвращаете дробные милисекунды, вы можете использовать тип данных System.Int64 (long in c #),Ваше значение находится в пределах допустимого диапазона для этого типа данных.Максимальное значение 1014 * для Int64 (long) составляет 9 223 372 036 854 775 807

.
...