3

由于 DateTime.AddDays() 需要一个double参数,我担心当您添加天数时,可能会出现一些舍入错误。例如,假设我有以下循环:

DateTime Now = DateTime.Today;
for (int i = 0; i < 365; ++i)
{
    Now = Now.AddDays(1);
    // do something
}

我担心现在可能会从午夜开始逐渐消失。我总是很想做这样的事情,这可能会慢一点,但可以缓解我的偏执:

for (int i = 0; i < 365; ++i)
{
    Now = Now.AddDays(1.01).Date;
    // do something
}
4

5 回答 5

11

由于DateTime将日期内部存储为 64 位整数,其中一个刻度表示 100 纳秒,因此不存在出错的风险。一天有 864,000,000,000 个刻度,Double精度至少为 15 位。因此,当四舍五入到刻度时,每个错误都会消失,因为如果等于一天,Double则分辨率比一个刻度更高。1.0

这不适用于AddYears(),因为如果等于一年,Double则没有足够的精度来表示一个刻度。1.0但是,如果您查看DateTime该类,您会发现设计尊重这一事实 -AddMonths()并且AddYears()具有整数和非浮点参数。

要检查这一点,只需执行以下代码。

DateTime now = DateTime.Now;

// Displays 864000000000 
Console.WriteLine(now.AddDays(1.0).Ticks - now.Ticks);
于 2009-04-20T16:21:08.360 回答
2

一般来说,我认为你担心用双精度四舍五入是正确的,因为并非所有实数都可以用双精度表示——例如,如果你将一天的 1/3 相加 3 次,你可能不会得到正好提前一天。但是,在这种情况下,1 是一个绝对可以表达的数字,因为您只是将它乘以另一个也绝对可以用双精度表达的数字(一天中的刻度数),您应该没问题。第二个样本可能是矫枉过正。

例子:

DateTime now = DateTime.Today;
for (int i = 0; i < 7; ++i )
{
    for (int j = 0; j < 7; ++j )
    {
         now = now.AddDays( 1 / 7.0 );
    }
}
Console.WriteLine( DateTime.Today);
Console.WriteLine( now );

结果(2009 年 4 月 20 日)

4/20/2009 12:00:00 AM
4/26/2009 11:59:59 PM
于 2009-04-20T16:24:01.367 回答
1

天数乘以一个整数(刻度),然后添加到DateTime. 当您传入一个整数时,您最终会添加整数个刻度。

另一方面,我不知道 .NET 对闰秒做了什么......我怀疑它使用了一个非常简单的模型,不会打扰它们,让你的代码没问题。

不要忘记添加时区会增加额外的复杂性 - 在本地添加一天可能会增加多于或少于一天的 UTC,反之亦然。

于 2009-04-20T16:22:42.273 回答
0

你说的远离午夜是什么意思?

运行时,第一个代码的最后日期为 4/20/2010 12:00:00 AM。
我认为这就是你所期望的。不是吗?

于 2009-04-20T16:20:11.077 回答
0

在您的示例中,我将 1 天添加到 DateTime 变量 100,000 次,但仍然以具有午夜时间值的日期结束。似乎没有理由担心。

我确信他们正在四舍五入到时间刻度,这消除了漂移的任何问题。

于 2009-04-20T16:20:15.073 回答