如何将时间向上舍入到最接近的X分钟?

Tim*_*imS 144 c# datetime rounding

有舍入一个简单的函数UPDateTime到最近的15分钟?

例如

2011-08-11 16:592011-08-11 17:00

2011-08-11 17:00 留下来 2011-08-11 17:00

2011-08-11 17:012011-08-11 17:15

dtb*_*dtb 260

DateTime RoundUp(DateTime dt, TimeSpan d)
{
    return new DateTime((dt.Ticks + d.Ticks - 1) / d.Ticks * d.Ticks, dt.Kind);
}
Run Code Online (Sandbox Code Playgroud)

例:

var dt1 = RoundUp(DateTime.Parse("2011-08-11 16:59"), TimeSpan.FromMinutes(15));
// dt1 == {11/08/2011 17:00:00}

var dt2 = RoundUp(DateTime.Parse("2011-08-11 17:00"), TimeSpan.FromMinutes(15));
// dt2 == {11/08/2011 17:00:00}

var dt3 = RoundUp(DateTime.Parse("2011-08-11 17:01"), TimeSpan.FromMinutes(15));
// dt3 == {11/08/2011 17:15:00}
Run Code Online (Sandbox Code Playgroud)

  • 为什么这样做?我很难想象这个. (17认同)
  • 这个解决方案只是作为扩展方法进入我的实用程序库. (11认同)
  • @dtb一个小的补充,否则它可能有点bug:你需要保持datetime类型;-)`DateTime RoundUp(DateTime dt,TimeSpan d){return new DateTime(((dt.Ticks + d.Ticks - 1 )/ d.Ticks)*d.Ticks,dt.Kind); }` (11认同)
  • @ user14 ..(+ d.Ticks - 1)确保在必要时将其向上舍入./和*是四舍五入的.示例第12轮到下一个5:(12 + 5 - 1)= 16,16/5 = 3(因为它是整数数据类型),3*5 = 15. tada :) (10认同)
  • 您是否使用此方法丢失DateTime对象中的信息?喜欢种类和时区,如果有设置? (4认同)
  • 如果有人需要此答案的圆形版本: DateTime RoundDown(DateTime dt, TimeSpan d) { return new DateTime(dt.Ticks / d.Ticks * d.Ticks, dt.Kind); } (4认同)

red*_*t84 98

提出了一个不涉及乘法除数 的解决方案long.

public static DateTime RoundUp(this DateTime dt, TimeSpan d)
{
    var modTicks = dt.Ticks % d.Ticks;
    var delta = modTicks != 0 ? d.Ticks - modTicks : 0;
    return new DateTime(dt.Ticks + delta, dt.Kind);
}

public static DateTime RoundDown(this DateTime dt, TimeSpan d)
{
    var delta = dt.Ticks % d.Ticks;
    return new DateTime(dt.Ticks - delta, dt.Kind);
}

public static DateTime RoundToNearest(this DateTime dt, TimeSpan d)
{
    var delta = dt.Ticks % d.Ticks;
    bool roundUp = delta > d.Ticks / 2;
    var offset = roundUp ? d.Ticks : 0;

    return new DateTime(dt.Ticks + offset - delta, dt.Kind);
}
Run Code Online (Sandbox Code Playgroud)

用法:

var date = new DateTime(2010, 02, 05, 10, 35, 25, 450); // 2010/02/05 10:35:25
var roundedUp = date.RoundUp(TimeSpan.FromMinutes(15)); // 2010/02/05 10:45:00
var roundedDown = date.RoundDown(TimeSpan.FromMinutes(15)); // 2010/02/05 10:30:00
var roundedToNearest = date.RoundToNearest(TimeSpan.FromMinutes(15)); // 2010/02/05 10:30:00
Run Code Online (Sandbox Code Playgroud)

  • 我确信这会比使用乘法和除法更快,但我的测试显示它不是.这超过10000000次迭代,模数法在我的机器上花了大约610ms,而mult/div方法需要大约500ms.我想FPU使旧的问题成为一个非问题.这是我的测试代码:http://pastie.org/8610460 (7认同)
  • 只是指出,模数是需要在 CPU 上进行除法运算的。但我同意使用整数除法的向下属性更优雅。 (2认同)

小智 19

如果你需要舍入到最近的时间间隔(而不是向上),那么我建议使用以下内容

    static DateTime RoundToNearestInterval(DateTime dt, TimeSpan d)
    {
        int f=0;
        double m = (double)(dt.Ticks % d.Ticks) / d.Ticks;
        if (m >= 0.5)
            f=1;            
        return new DateTime(((dt.Ticks/ d.Ticks)+f) * d.Ticks);
    }
Run Code Online (Sandbox Code Playgroud)


rea*_*art 17

我已经看到了许多有用的实现,例如来自 @dtb 或 @redent84 的实现。由于性能差异可以忽略不计,因此我远离位移并简单地创建了可读代码。我经常在我的实用程序库中使用这些扩展。

public static class DateTimeExtensions
{
    public static DateTime RoundToTicks(this DateTime target, long ticks) => new DateTime((target.Ticks + ticks / 2) / ticks * ticks, target.Kind);
    public static DateTime RoundUpToTicks(this DateTime target, long ticks) => new DateTime((target.Ticks + ticks - 1) / ticks * ticks, target.Kind);
    public static DateTime RoundDownToTicks(this DateTime target, long ticks) => new DateTime(target.Ticks / ticks * ticks, target.Kind);

    public static DateTime Round(this DateTime target, TimeSpan round) => RoundToTicks(target, round.Ticks);
    public static DateTime RoundUp(this DateTime target, TimeSpan round) => RoundUpToTicks(target, round.Ticks);
    public static DateTime RoundDown(this DateTime target, TimeSpan round) => RoundDownToTicks(target, round.Ticks);

    public static DateTime RoundToMinutes(this DateTime target, int minutes = 1) => RoundToTicks(target, minutes * TimeSpan.TicksPerMinute);
    public static DateTime RoundUpToMinutes(this DateTime target, int minutes = 1) => RoundUpToTicks(target, minutes * TimeSpan.TicksPerMinute);
    public static DateTime RoundDownToMinutes(this DateTime target, int minutes = 1) => RoundDownToTicks(target, minutes * TimeSpan.TicksPerMinute);

    public static DateTime RoundToHours(this DateTime target, int hours = 1) => RoundToTicks(target, hours * TimeSpan.TicksPerHour);
    public static DateTime RoundUpToHours(this DateTime target, int hours = 1) => RoundUpToTicks(target, hours * TimeSpan.TicksPerHour);
    public static DateTime RoundDownToHours(this DateTime target, int hours = 1) => RoundDownToTicks(target, hours * TimeSpan.TicksPerHour);

    public static DateTime RoundToDays(this DateTime target, int days = 1) => RoundToTicks(target, days * TimeSpan.TicksPerDay);
    public static DateTime RoundUpToDays(this DateTime target, int days = 1) => RoundUpToTicks(target, days * TimeSpan.TicksPerDay);
    public static DateTime RoundDownToDays(this DateTime target, int days = 1) => RoundDownToTicks(target, days * TimeSpan.TicksPerDay);
}
Run Code Online (Sandbox Code Playgroud)


Vla*_*den 8

void Main()
{
    var date1 = new DateTime(2011, 8, 11, 16, 59, 00);
    date1.Round15().Dump();

    var date2 = new DateTime(2011, 8, 11, 17, 00, 02);
    date2.Round15().Dump();

    var date3 = new DateTime(2011, 8, 11, 17, 01, 23);
    date3.Round15().Dump();

    var date4 = new DateTime(2011, 8, 11, 17, 00, 00);
    date4.Round15().Dump();
}

public static class Extentions
{
    public static DateTime Round15(this DateTime value)
    {   
        var ticksIn15Mins = TimeSpan.FromMinutes(15).Ticks;

        return (value.Ticks % ticksIn15Mins == 0) ? value : new DateTime((value.Ticks / ticksIn15Mins + 1) * ticksIn15Mins);
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

8/11/2011 5:00:00 PM
8/11/2011 5:15:00 PM
8/11/2011 5:15:00 PM
8/11/2011 5:00:00 PM
Run Code Online (Sandbox Code Playgroud)

  • `2011-08-11 17:00:01`被截断为"2011-08-11 17:00:00" (3认同)

Nic*_*rey 5

因为我讨厌重新发明轮子,所以我可能会遵循以下算法将DateTime值四舍五入到指定的时间增量(时间跨度):

  • DateTime要四舍五入的值转换为代表整数的整数和小数的十进制浮点值TimeSpan
  • 使用将其四舍五入为整数Math.Round()
  • 通过将舍入的整数乘以TimeSpan单位中的刻度数,可以缩小刻度。
  • DateTime从四舍五入的滴答数实例化一个新值,并将其返回给调用方。

这是代码:

public static class DateTimeExtensions
{

    public static DateTime Round( this DateTime value , TimeSpan unit )
    {
        return Round( value , unit , default(MidpointRounding) ) ;
    }

    public static DateTime Round( this DateTime value , TimeSpan unit , MidpointRounding style )
    {
        if ( unit <= TimeSpan.Zero ) throw new ArgumentOutOfRangeException("unit" , "value must be positive") ;

        Decimal  units        = (decimal) value.Ticks / (decimal) unit.Ticks ;
        Decimal  roundedUnits = Math.Round( units , style ) ;
        long     roundedTicks = (long) roundedUnits * unit.Ticks ;
        DateTime instance     = new DateTime( roundedTicks ) ;

        return instance ;
    }

}
Run Code Online (Sandbox Code Playgroud)


sou*_*man 5

我的版本

DateTime newDateTimeObject = oldDateTimeObject.AddMinutes(15 - oldDateTimeObject.Minute % 15);
Run Code Online (Sandbox Code Playgroud)

作为一种方法,它会像这样锁定

public static DateTime GetNextQuarterHour(DateTime oldDateTimeObject)
{
    return oldDateTimeObject.AddMinutes(15 - oldDateTimeObject.Minute % 15);
}
Run Code Online (Sandbox Code Playgroud)

并被这样称呼

DateTime thisIsNow = DateTime.Now;
DateTime nextQuarterHour = GetNextQuarterHour(thisIsNow);
Run Code Online (Sandbox Code Playgroud)