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:
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!
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 );
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));
}
}
You should also be clear if you want your rounding to:
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.
只需使用Ticks,使用它来划分,下限/ ceil / round值,并将其相乘。
如果您只想将小时数舍入到天花板上
Console.WriteLine(DateTime.Now.ToString("M/d/yyyy hh:00:00"));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.