【问题标题】:Can DateTime conversion between Java and C# introduce errors?Java 和 C# 之间的 DateTime 转换会引入错误吗?
【发布时间】:2011-11-03 01:22:56
【问题描述】:

背景

我正在使用 Apache 的 NMS 库与 ActiveMq 通信。每条发送的消息都由生产者标记时间戳,我通过从DateTime.UtcNow 中减去时间戳来查看消息延迟,我希望看到 0-100 毫秒的延迟,但我看到报告的延迟在 -1000 到 1000 之间小姐。显然负延迟是没有意义的,所以我最初怀疑系统时钟不同步,但我现在已经独立确认它们是正确的,并且在 20 毫秒内。

更多背景

Measuring broadcast message latency using system clock, good idea?

问题

我现在认为差异可能是由于 .Net 和 Java 之间处理日期的方式造成的。

  • 从 Java 到 .Net 的转换是否有损?
  • 转换能否解释我观察到的较大的负时间跨度?
  • 还有什么可以解释时差的吗?

MessageProducer.cs -- 生产者设置 NMSTimestamp

activeMessage.NMSTimestamp = DateTime.UtcNow;

ActiveMqMessage.cs -- NMSTimestamp 转换为 Java 时间并存储在 Message 上

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

Message.cs -- Timestamp 保存有线格式的日期,消息编组器直接设置此值

// 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;

【问题讨论】:

  • 日期时间如何以有线格式表示?实际上是否包括毫秒?常见的日期时间格式通过线路停止在“秒”并添加偏移量,但没有毫秒。
  • @Marvin - 它只是作为一个long传输,所有的转换都在上面进行
  • 刚刚发现这个:experts-exchange.com/Programming/Languages/C_Sharp/… 似乎是相关的。
  • @Marvin:不敢相信你发布了那个.. LOL

标签: c# java .net datetime nms


【解决方案1】:

是的,与 Java 时间的转换是有损的。这是因为 Java 时间不如 Windows 时间精确。与不同时间格式的转换保证精确到毫秒而不会丢失。不过,更精确的 Windows Ticks 将会丢失。

NMS DateTime 实用程序转换功能正常工作。您遇到的错误来自您的延迟计算代码。您正在使用 var 类型,这就是您的错误所在。TotalMilliseconds 返回一个 double 值,这将创建一个舍入误差。解决方法是将值截断为整毫秒,而不是部分毫秒,因为如上所述是有损的。尝试使用具有 long 强类型的以下代码来计算延迟:

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

【讨论】:

  • 严格来说var不是一个类型;在这种情况下,它是 double 的同义词,因为 TotalMilliseconds 是双精度数。所以它本身不会引入任何错误。
  • 严格来说,var是一个隐式类型。来自 MSDN:“从 Visual C# 3.0 开始,在方法范围内声明的变量可以具有隐式类型 var。”这是引入错误的原因,因为隐式类型解析为双精度。欲了解更多信息:msdn.microsoft.com/en-us/library/bb384061.aspx
猜你喜欢
  • 1970-01-01
  • 2014-01-08
  • 2017-06-25
  • 1970-01-01
  • 1970-01-01
  • 2017-03-28
  • 1970-01-01
  • 2012-11-22
相关资源
最近更新 更多