C# 舍入日期时间对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1393696/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 16:01:14  来源:igfitidea点击:

Rounding DateTime objects

c#algorithm

提问by grenade

I want to round dates/times to the nearest interval for a charting application. I'd like an extension method signature like follows so that the rounding can be acheived for any level of accuracy:

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

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

The idea is that if I pass in a timespan of ten minutes, it will round to the nearest ten minute interval. I can't get my head around the implementation and am hoping one of you will have written or used something similar before.

这个想法是,如果我通过十分钟的时间跨度,它将四舍五入到最接近的十分钟间隔。我无法理解实现,希望你们中的一个人以前写过或使用过类似的东西。

I think either a floor, ceiling or nearest implementation is fine.

我认为地板、天花板或最近的实施都可以。

Any ideas?

有任何想法吗?

Edit: Thanks to @tvanfosson & @ShuggyCoUk, the implementation looks like this:

编辑:感谢@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);
    }
}

And is called like so:

并被这样调用:

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

Cheers!

干杯!

采纳答案by tvanfosson

Floor

地面

long ticks = date.Ticks / span.Ticks;

return new DateTime( ticks * span.Ticks );

Round (up on midpoint)

圆(在中点)

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

return new DateTime( ticks * span.Ticks );

Ceiling

天花板

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

return new DateTime( ticks * span.Ticks );

回答by Lucero

Just use the Ticks, using that to divide, floor/ceil/round the value, and multiply it back.

只需使用刻度,使用它来划分,地板/天花板/四舍五入值,然后乘以它。

回答by ShuggyCoUk

You should also be clear if you want your rounding to:

如果您希望四舍五入为:

  1. be to the start, end or middle of the interval
    • start is the easiest and often the expected but you should be clear in your initial spec.
  2. How you want boundary cases to round.
    • normally only an issue if you are rounding to the middle rather than the end.
    • Since rounding to the middle is an attempt at a bias free answer you need to use something like Bankers Roundingtechnically round half even to be truly free from bias.
  1. 到区间的开始、结束或中间
    • start 是最简单的,通常也是预期的,但您应该在初始规范中明确。
  2. 您希望边界情况如何舍入。
    • 通常只有在您四舍五入到中间而不是末尾时才会出现问题。
    • 由于四舍五入是对无偏见答案的尝试,因此您需要使用银行家四舍五入之类的技术,从技术上讲,甚至要真正消除偏见。

It is quite likely that you really only care about the first point but in these 'simple' questions the resulting behaviour can have far reaching consequences as you use it in the real world (often at the intervals adjacent to zero)

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

tvanfosson's solution's cover all the cases listed in 1. The midpoint example is biased upwards. It is doubtful that this would be a problem in time related rounding.

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

回答by aj.toulan

This will let you round to any interval given. It's also slightly faster than dividing and then multiplying the ticks.

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

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

回答by Priyanka

If you just want to round up the Hour to Ceiling Value

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

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