online - test dome c#
Redondeo de objetos DateTime (5)
Esto te permitirá redondear a cualquier intervalo dado. También es un poco más rápido que dividir y luego multiplicar los tics.
private static DateTime Floor(DateTime dateTime, TimeSpan interval)
{
return dateTime.AddTicks(-(dateTime.Ticks % interval.Ticks));
}
private static DateTime Ceiling(DateTime dateTime, TimeSpan interval)
{
var overflow = dateTime.Ticks % interval.Ticks;
return overflow == 0 ? dateTime : dateTime.AddTicks(interval.Ticks - overflow);
}
private static DateTime Round(DateTime dateTime, TimeSpan interval)
{
var halfIntervalTicks = (interval.Ticks + 1) >> 1;
return dateTime.AddTicks(halfIntervalTicks - ((dateTime.Ticks + halfIntervalTicks) % interval.Ticks));
}
Quiero redondear fechas / horas al intervalo más cercano para una aplicación de gráficos. Me gustaría una firma del método de extensión de la siguiente manera para que el redondeo se pueda lograr con cualquier nivel de precisión:
static DateTime Round(this DateTime date, TimeSpan span);
La idea es que si paso en un intervalo de tiempo de diez minutos, se redondeará al intervalo de diez minutos más cercano. No entiendo la implementación y espero que alguno de ustedes haya escrito o usado algo similar antes.
Creo que bien el piso, el techo o la implementación más cercana está bien.
¿Algunas ideas?
Editar: Gracias a @tvanfosson & @ShuggyCoUk, la implementación se ve así:
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);
}
}
Y se llama así:
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));
...
¡Aclamaciones!
Piso
long ticks = date.Ticks / span.Ticks;
return new DateTime( ticks * span.Ticks );
Redondo (arriba en el punto medio)
long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;
return new DateTime( ticks * span.Ticks );
Techo
long ticks = (date.Ticks + span.Ticks - 1)/ span.Ticks;
return new DateTime( ticks * span.Ticks );
Si solo quieres redondear la Hora a Valor de techo
Console.WriteLine(DateTime.Now.ToString("M/d/yyyy hh:00:00"));
Simplemente use los Ticks, use eso para dividir, piso / ceile / redondee el valor, y multiplíquelo de regreso.
También debe ser claro si quiere que su redondeo a:
- ser al comienzo, al final o al medio del intervalo
- el inicio es el más fácil y, a menudo, el esperado, pero debe tener en cuenta su especificación inicial.
- Cómo desea que redondeen los casos de límite.
- normalmente solo es un problema si se está redondeando hacia el centro en lugar de hacia el final.
- Dado que el redondeo al medio es un intento de una respuesta libre de sesgo, usted necesita usar algo como Bankers Rounding, técnicamente la mitad redonda, incluso para estar verdaderamente libre de prejuicios.
Es bastante probable que realmente solo se preocupe por el primer punto, pero en estas preguntas "simples" el comportamiento resultante puede tener consecuencias de largo alcance al usarlo en el mundo real (a menudo en los intervalos adyacentes a cero).
La solución de tvanfosson cubre todos los casos enumerados en 1. El ejemplo del punto medio está sesgado hacia arriba. Es dudoso que esto sea un problema en el redondeo relacionado con el tiempo.