TimeSpan FromMilliseconds奇怪的实现?

时间:2011-03-27 16:11:58

标签: c# .net timespan

我最近在.net timepan实现中遇到了一些奇怪的行为。

        TimeSpan test = TimeSpan.FromMilliseconds(0.5);
        double ms = test.TotalMilliseconds; // Returns 0

FromMilliseconds采用double作为参数。但是,似乎内部的值是四舍五入的。

如果我使用5000个滴答(.5毫秒)实例化新的时间跨度,则TotalMilliseconds的值是正确的。

查看反射器中的TimeSpan实现会发现输入实际上已转换为long。

为什么Microsoft将FromMilliseconds方法设计为使用double参数而不是long(因为根据此实现,double值是无用的)?

5 个答案:

答案 0 :(得分:24)

首先考虑的是他们为什么选择 double 作为返回值。使用 long 将是一个明显的选择。虽然已经有一个很长的完美的属性,但Ticks是明确的,单位为100纳秒。但他们选择了两倍,可能是为了返回一个小数值。

然而,这产生了一个新问题,一个可能只是稍后才发现的问题。双倍只能存储15位有效数字。 TimeSpan可以存储10,000年。 非常希望从TimeSpan转换为毫秒,然后再转换回TimeSpan并获得相同的值。

双重不可能。算一算:10000年约为10000 x 365.4 x 24 x 3600 x 1000 = 315,705,600,000,000毫秒。计算15位数,最好是双倍数,你可以完全一毫秒作为仍然可以存储而没有舍入误差的最小单位。任何额外的数字都是随机噪音。

在摇滚和硬地之间,设计师(测试人员?)在从TimeSpan转换为毫秒时必须选择舍入值。或者稍后从毫秒到TimeSpan。他们选择早做,这是一个勇敢的决定。

使用Ticks属性并乘以1E-4来解决问题,以获得毫秒数。

答案 1 :(得分:3)

这显然是设计的。 documentation同样说:

  

value参数转换为   滴答滴答,滴答数是   用于初始化新的TimeSpan。   因此,价值只会是   认为精确到最近   毫秒。

答案 2 :(得分:2)

接受双重是一种逻辑设计。你可以有几分之一毫秒。

内部发生的是实施设计。即使所有当前(CLI的实现)的实现都是先将其舍入,但未来也不一定如此。

答案 3 :(得分:1)

您的代码问题实际上是第一行,您可以在其中调用FromMilliseconds。如前所述,文档中的备注说明如下:

  

value 参数转换为刻度,并且该刻度数用于初始化新的TimeSpan。因此, value 仅被认为是精确到最接近的毫秒。

实际上,这种说法既不正确也不合逻辑。以相反的顺序:

  • 蜱被定义为“一百纳秒”。根据这个定义,文档应该写成:

      

    因此, value 只会被认为是精确到最近的毫秒 刻度,或者是千万分之一秒

  • 由于存在错误或疏忽,在初始化新TimeSpan实例之前,参数不会直接转换为刻度。这可以看作in the reference source for TimeSpan,其中millis值在之前舍入为其转换为滴答,而不是之后。如果要保留最大精度,那么这行代码应该如下所示(并且将删除之前的0.5毫秒3行的调整):

    return new TimeSpan((long)(millis * TicksPerMillisecond));
    

要点:

应更新各种TimeSpan.From*的文档({1}}除外),以说明参数舍入到最接近的毫秒(不包括对刻度的引用)。

答案 4 :(得分:0)

或者,你可以这样做:

double x = 0.4;

TimeSpan t = TimeSpan.FromTicks((long)(TimeSpan.TicksPerMillisecond * x)); // where x can be a double
double ms = t.TotalMilliseconds; //return 0.4

- 讽刺

TimeSpan将双倍的毫秒转换为滴答,以便" 显然"你可以拥有一个粒度小于1毫秒的TimeSpan。

- /讽刺

- 这根本不是很明显...... 为什么在.FromMilliseconds方法中没有做到这一点超出了我的范围。