Может ли преобразование DateTime между Java и C # вводить ошибки? - PullRequest
2 голосов
/ 15 февраля 2011

Фон

Я использую библиотеку Apache NMS для общения с ActiveMq. Каждое отправленное сообщение имеет метку времени от производителя, я смотрю на задержку сообщения, вычитая временную метку из DateTime.UtcNow, я ожидаю увидеть задержки 0-100 мс, но вместо этого я вижу, что задержки составляют от -1000 до 1000 Миз. Очевидно, что отрицательные задержки не имеют смысла, поэтому я изначально подозревал, что системные часы не синхронизированы, однако теперь я независимо подтвердил, что они правильные и находятся в пределах 20 мс друг от друга.

Больше фона

Измерение задержки широковещательного сообщения с использованием системных часов, хорошая идея?

Вопрос

Теперь я считаю, что расхождения могут быть связаны с тем, как обрабатываются даты в .Net и Java.

  • Потеряно ли преобразование из Java в / из .Net раз?
  • Могут ли преобразования объяснить большие отрицательные промежутки времени, которые я наблюдал?
  • Есть ли что-то еще, что могло бы объяснить разницу во времени?

MessageProducer.cs - Производитель наборов NMSTimestamp

activeMessage.NMSTimestamp = DateTime.UtcNow;

ActiveMqMessage.cs - NMSTimestamp преобразует время Java и сохраняет в сообщении

...
public DateTime NMSTimestamp
{
    get { return DateUtils.ToDateTime(Timestamp); }
    set
    {
        Timestamp = DateUtils.ToJavaTimeUtc(value);
        if(timeToLive.TotalMilliseconds > 0)
        {
            Expiration = Timestamp + (long) timeToLive.TotalMilliseconds;
        }
    }
}
...

Message.cs - Временная метка содержит дату в формате проводника, маршаллер сообщения устанавливает это значение напрямую

// ActiveMqMessage extends Message
...
public long Timestamp
{
   get { return timestamp; }
   set { this.timestamp = value; }
}
...

DateUtils.cs - Используется для выполнения преобразований

namespace Apache.NMS.Util
{
    public class DateUtils
    {
        /// <summary>
        /// The start of the Windows epoch
        /// </summary>
        public static readonly DateTime windowsEpoch = new DateTime(1601, 1, 1, 0, 0, 0, 0);
        /// <summary>
        /// The start of the Java epoch
        /// </summary>
        public static readonly DateTime javaEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);

        /// <summary>
        /// The difference between the Windows epoch and the Java epoch
        /// in milliseconds.
        /// </summary>
        public static readonly long epochDiff; /* = 1164447360000L; */

        static DateUtils()
        {
            epochDiff = (javaEpoch.ToFileTimeUtc() - windowsEpoch.ToFileTimeUtc())
                            / TimeSpan.TicksPerMillisecond;
        }

        public static long ToJavaTime(DateTime dateTime)
        {
            return (dateTime.ToFileTime() / TimeSpan.TicksPerMillisecond) - epochDiff;
        }

        public static DateTime ToDateTime(long javaTime)
        {
            return DateTime.FromFileTime((javaTime + epochDiff) * TimeSpan.TicksPerMillisecond);
        }

        public static long ToJavaTimeUtc(DateTime dateTime)
        {
            return (dateTime.ToFileTimeUtc() / TimeSpan.TicksPerMillisecond) - epochDiff;
        }

        public static DateTime ToDateTimeUtc(long javaTime)
        {
            return DateTime.FromFileTimeUtc((javaTime + epochDiff) * TimeSpan.TicksPerMillisecond);
        }
    }
}

Мой код рассчитывает задержку следующим образом

var latency = (DateTime.UtcNow - msg.NMSTimestamp).TotalMilliseconds;

1 Ответ

3 голосов
/ 02 ноября 2011

Да, преобразование в / из времени Java с потерями. Это связано с тем, что время Java не так точно, как время Windows. Преобразование в / из различных форматов времени гарантируется с точностью до миллисекунды без потерь. Однако более точные отметки Windows будут потеряны.

Функции преобразования утилиты NMS DateTime работают правильно. Ошибка, с которой вы столкнулись, исходит из кода расчета задержки. Вы используете тип var , и именно здесь возникает ваша ошибка. TotalMilliseconds возвращает значение double , и это приведет к ошибке округления. Исправление состоит в том, чтобы усечь значение до целых миллисекунд, а не частичных миллисекунд, поскольку это с потерями, как описано выше. Попробуйте использовать следующий код со строгим набором long для расчета задержки:

long latency = System.Math.floor((DateTime.UtcNow - msg.NMSTimestamp).TotalMilliseconds);
...