在C#中有更好的方法将DateTime四舍五入到最接近的5秒吗?

我想将DateTime四舍五入到最接近的5秒。 这是我目前正在做的方式,但我想知道是否有更好或更简洁的方式?

DateTime now = DateTime.Now; int second = 0; // round to nearest 5 second mark if (now.Second % 5 > 2.5) { // round up second = now.Second + (5 - (now.Second % 5)); } else { // round down second = now.Second - (now.Second % 5); } DateTime rounded = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, second); 

请注意,我已经找到了前两个问题,但是它们会截断而不是缩短时间。

DateTime的Ticks计数表示100纳秒的间隔,因此您可以通过舍入到最近的50000000-tick间隔来舍入到最接近的5秒,如下所示:

  DateTime now = DateTime.Now; DateTime rounded = new DateTime(((now.Ticks + 25000000) / 50000000) * 50000000); 

这更简洁,但不一定更好。 这取决于您是否更喜欢简洁和速度而不是代码清晰度。 你的理解更容易理解。

(抱歉复活;我认识到这是一个陈旧且回答的问题 – 只是为了谷歌而添加了一些额外的代码。)

我从JayMcClellan的回答开始,但后来我希望它更通用,四舍五入到任意间隔(不仅仅是5秒)。 因此,我最终将Jay的方法留给了一个在刻度Math.Round使用Math.Round的方法,并将其放入一个可以采用任意间隔的扩展方法,并且还提供了更改舍入逻辑的选项(银行家的舍入与远离零的对比)。 我发布在这里,以防这对其他人也有帮助:

  public static TimeSpan Round(this TimeSpan time, TimeSpan roundingInterval, MidpointRounding roundingType) { return new TimeSpan( Convert.ToInt64(Math.Round( time.Ticks / (decimal)roundingInterval.Ticks, roundingType )) * roundingInterval.Ticks ); } public static TimeSpan Round(this TimeSpan time, TimeSpan roundingInterval) { return Round(time, roundingInterval, MidpointRounding.ToEven); } public static DateTime Round(this DateTime datetime, TimeSpan roundingInterval) { return new DateTime((datetime - DateTime.MinValue).Round(roundingInterval).Ticks); } 

它不会因为效率低而赢得任何奖项,但我发现它易于阅读且直观易用。 用法示例:

 new DateTime(2010, 11, 4, 10, 28, 27).Round(TimeSpan.FromMinutes(1)); // rounds to 2010.11.04 10:28:00 new DateTime(2010, 11, 4, 13, 28, 27).Round(TimeSpan.FromDays(1)); // rounds to 2010.11.05 00:00 new TimeSpan(0, 2, 26).Round(TimeSpan.FromSeconds(5)); // rounds to 00:02:25 new TimeSpan(3, 34, 0).Round(TimeSpan.FromMinutes(37); // rounds to 03:42:00...for all your round-to-37-minute needs 

就像你提到的那样,截断它很容易。 所以,只需添加2.5秒,然后截断。

我想不出更好的方法,虽然我可能会考虑圆方法:

 static int Round(int n, int r) { if ((n % r) <= r / 2) { return n - (n % r); } return n + (r - (n % r)); } 

此外,%返回一个int,所以将它与2.5比较让我觉得有点奇怪,即使它是正确的。 我用> = 3。

怎么样(将几个答案混合在一起)? 我认为它很好地传达了意义,并且应该优雅地处理边缘情况(四舍五入到下一分钟),因为AddSeconds

 // truncate to multiple of 5 int second = 5 * (int) (now.Second / 5); DateTime dt = new DateTime(..., second); // round-up if necessary if (now.Second % 5 > 2.5) { dt = dt.AddSeconds(5); } 

Jay所示的Ticks方法更简洁,但可读性稍差。 如果使用该方法,至少参考TimeSpan.TicksPerSecond

我无法认识到C#和一块肥皂之间的区别(好吧,当我最初写这个答案时我不能,这些年来情况发生了很大变化)但是,如果你想要更简洁的话解决方案,我只是将整个事情放在一个函数中 – 在代码中比在对函数的简单调用中更简洁:

 DateTime rounded = roundTo5Secs (DateTime.Now); 

然后你可以在函数中放入你想要的任何东西,并记录它是如何工作的,例如(假设这些都是整数运算):

 secBase = now.Second / 5; secExtra = now.Second % 5; if (secExtra > 2) { return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, secBase + 5); } return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, secBase); 

如果secBase转到60,你可能还需要一些额外的检查(除非C#DateTime对象足够智能以提高分钟(如果分钟达到60则为小时,依此类推)。

从技术上讲,你只能在几秒钟内正确地舍入到奇数间隔。

2,4,6,8,10 < - 没问题

如果您按时间间隔“分配”时间,并且抖动较低,则截断更容易处理。

如果你能够以500毫秒标记传递毫秒和圆形,你将能够达到奇数秒并且还可以减少抖动的影响或完全消除它。