为什么将DateTime格式化为字符串时会截断而不是四舍五入毫秒?

15

Double 格式化为字符串时会进行四舍五入。例如:

Console.WriteLine(12345.6.ToString("F0"));

输出

12346

但是,当DateTime格式化为字符串时会使用截断。例如:

var ci = CultureInfo.InvariantCulture;
var dateTime = DateTime.Parse("2011-09-14T15:18:42.999", ci);
Console.WriteLine(dateTime.ToString("o", ci));
Console.WriteLine(dateTime.ToString("s", ci));
Console.WriteLine(dateTime.ToString("yyyy-MM-hhThh:mm:ss.f", ci));

输出

2011-09-14T15:18:42.9990000
2011-09-14T15:18:42
2011-09-14T15:18:42.9

这种行为背后的推理(如果有的话)是什么?


将时间舍入到最近的秒可以通过在格式化为字符串之前添加半秒来实现:

var ci = CultureInfo.InvariantCulture;
var dateTime = DateTime.Parse("2010-12-31T23:59:59.999", ci);
Console.WriteLine(dateTime.ToString("s", ci));
var roundedDateTime = dateTime.AddMilliseconds(500);
Console.WriteLine(roundedDateTime.ToString("s", ci));

输出

2010-12-31T23:59:59
2011-01-01T00:00:00
3个回答

19

这有点主观,但是我认为舍入日期和时间值而不是将其截断会导致“更加”意外的行为。

例如,舍入new DateTime(2011, 1, 1, 23, 59, 59, 999)将导致全新的一天。这听起来比仅仅截断该值要奇怪得多。


1
如果新的一天是在下一年,那么舍入会一直级联到那一年。在大多数情况下,这可能不是您想要的日期处理方式。 - Martin Liversage
1
也许另一种思考方式是:时间单位是时间跨度而不是时间点。一个时间单位完全延伸到下一个(相同的)单位的开始。因此,例如,在星期二的0.99999处仍然被认为是“星期二”,而不是“星期三”。 - Spike0xff

1

这是一个老问题,但它被从一个新问题中引用,并讨论了舍入与否的原因(当然是有效的),但没有回答该问题。

不进行四舍五入的原因是,ToString 只会打印您要求的日期/时间部分。

因此,例如,它也不会将其舍入到最接近的分钟:

Console.WriteLine(dateTime.ToString("yyyy-MM-hhThh:mm", ci));

输出:

2011-09-03T03:18

没有参数时,ToString 使用您的环境的默认日期/时间格式字符串。

0

在最后的测量单位上,如果事件以该频率发生,舍入会大大减少混叠。

例如,如果抖动使得一个一秒钟的数据帧在第二秒钟进入2毫秒,下一个帧在同一帧中的990毫秒到达,它们都将被标记为在同一秒钟内。仅有几毫秒的抖动就会导致许多分散的非唯一键值。

舍入会将它们清晰地放入几秒钟中,直到抖动变得更加严重,例如+/- 499毫秒。

舍入的目的是防止分辨率无限制地增加。当不确定性远低于分辨率时,它会大大减少混叠。

“级联”只能发生在边界的分辨率以下。例如,年份的切换似乎很惊人,但这只能发生在距离新年午夜不到一秒钟(或毫秒等)的时间内。对此没有什么意外或特别不准确的地方。

要真正防止混叠(同一时间两次提及),您需要在舍入后实施抗混叠(如图形中所做)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接