舍入DateTime对象

时间:2009-09-08 12:21:49

标签: c# algorithm

我想将日期/时间舍入到图表应用程序的最近区间。我想要一个像下面这样的扩展方法签名,以便可以实现任何精确度的舍入:

static DateTime Round(this DateTime date, TimeSpan span);

这个想法是,如果我通过十分钟的时间跨度,它将会绕到最接近的十分钟间隔。我无法理解实施情况,并希望你们中的一个人之前会写过或使用类似的东西。

我认为楼层,天花板或最近的实施方案都可以。

有什么想法吗?

编辑:感谢@tvanfosson& @ShuggyCoUk,实现如下:

public static class DateExtensions {
    public static DateTime Round(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;
        return new DateTime(ticks * span.Ticks);
    }
    public static DateTime Floor(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks / span.Ticks);
        return new DateTime(ticks * span.Ticks);
    }
    public static DateTime Ceil(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks + span.Ticks - 1) / span.Ticks;
        return new DateTime(ticks * span.Ticks);
    }
}

并且这样称呼:

DateTime nearestHour = DateTime.Now.Round(new TimeSpan(1,0,0));
DateTime minuteCeiling = DateTime.Now.Ceil(new TimeSpan(0,1,0));
DateTime weekFloor = DateTime.Now.Floor(new TimeSpan(7,0,0,0));
...

干杯!

5 个答案:

答案 0 :(得分:119)

地板

long ticks = date.Ticks / span.Ticks;

return new DateTime( ticks * span.Ticks );

回合(中点上升)

long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;

return new DateTime( ticks * span.Ticks );

天花板

long ticks = (date.Ticks + span.Ticks - 1)/ span.Ticks;

return new DateTime( ticks * span.Ticks );

答案 1 :(得分:33)

这将让你四舍五入到给定的任何间隔。它也比分割然后乘以刻度稍快。

public static class DateTimeExtensions
{
  public static DateTime Floor(this DateTime dateTime, TimeSpan interval)
  {
    return dateTime.AddTicks(-(dateTime.Ticks % interval.Ticks));
  }

  public static DateTime Ceiling(this DateTime dateTime, TimeSpan interval)
  {
    var overflow = dateTime.Ticks % interval.Ticks;

    return overflow == 0 ? dateTime : dateTime.AddTicks(interval.Ticks - overflow);
  }

  public static DateTime Round(this DateTime dateTime, TimeSpan interval)
  {
    var halfIntervalTicks = (interval.Ticks + 1) >> 1;

    return dateTime.AddTicks(halfIntervalTicks - ((dateTime.Ticks + halfIntervalTicks) % interval.Ticks));
  }
}

答案 2 :(得分:10)

如果你想要进行四舍五入,你也应该清楚:

  1. 到间隔的开始,结束或中间
    • 开始是最简单的,通常是预期的,但你应该在你的初始规范中明确。
  2. 您希望边界情况如何变圆。
    • 通常只是一个问题,如果你正在向中间而不是结束。
    • 由于向中间舍入是试图获得无偏见的答案,因此您需要使用类似Bankers Rounding之类的技术,即使是真正没有偏见也是如此。
  3. 很可能你真的只关心第一点,但在这些“简单”的问题中,当你在现实世界中使用它时(通常在零点附近),所产生的行为会产生深远的影响。 p>

    tvanfosson的解决方案涵盖了1中列出的所有案例。 中点示例向上偏向上。令人怀疑的是,这将成为与时间相关的四舍五入的问题。

答案 3 :(得分:2)

只需使用Ticks,使用它来划分,下限/ ceil / round值,并将其相乘。

答案 4 :(得分:-3)

如果您只想将小时数舍入到天花板值

Console.WriteLine(DateTime.Now.ToString("M/d/yyyy hh:00:00"));