舍入DateTime对象


105

我想将日期/时间四舍五入到制图应用程序的最近间隔。我想要如下扩展方法签名,以便可以达到任何精度级别的舍入:

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));
...

干杯!


1
这里的某些实现的效果也会有所帮助:stackoverflow.com/questions/766626/...
马特·汉密尔顿


3
不要忘记将原始DateTimeKind添加到新创建的日期,例如:new DateTime(ticks * span.Ticks,date.Kind);
上午

Answers:


130

地板

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 );

5
我最近遇到了一个问题,其中没有保存DateTimeKind。对每种方法的最后一行进行以下调整对我的情况有所帮助:return new DateTime(ticks * span.Ticks, date.Kind);
Peet

39

这将使您舍入到给定的任何间隔。它也比除然后乘刻度的速度稍快。

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));
  }
}

11

如果要四舍五入到以下位置,也应该清楚一点:

  1. 到间隔的开始,结束或中间
    • start是最简单的方法,通常是预期的方法,但是您应该在初始规格中清楚一点。
  2. 您希望边界案例如何取整。
    • 通常,只有四舍五入而不是最后一个问题才是问题。
    • 由于四舍五入是为了寻求无偏差的答案,因此您需要使用类似Bankers Rounding的技术将其四舍五入,甚至要真正摆脱偏差。

您很可能只关心第一个问题,但是在这些“简单”问题中,当您在现实世界中使用行为时,所产生的行为可能会产生深远的影响(通常在零附近的时间间隔)

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


3

只需使用“刻度”,即可使用该刻度对值进行除法,下限/上限/四舍五入并将其相乘。


-2

如果您只想将小时数舍入为最高价值

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

OP请求将DateTime作为返回对象。
aj.toulan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.