2010-03-23 21 views
12

Necesito redondear las horas según los minutos en una variable DateTime. La condición es: si los minutos son menores que 30, los minutos deben configurarse en cero y no deben cambiarse a horas; de lo contrario, los minutos> = 30, las horas deben establecerse en horas + 1 y los minutos nuevamente se ponen en cero. Los segundos son ignorados.Cómo redondear las horas en función de los minutos (horas + 0 si mín <30, horas + 1 en caso contrario)?

ejemplo:
11/08/2008 04:30:49 debe convertirse en 11/08/2008 05:00:00
y 11/08/2008 04:29:49 debe convertirse en 11/08/2008 04:00:00

He escrito código que funciona perfectamente bien, pero sólo quería saber un mejor método si se podría escribir y también apreciaría método alternativo (s)

string date1 = "11/08/2008 04:30:49"; 
DateTime startTime; 
DateTime.TryParseExact(date1, "MM/dd/yyyy HH:mm:ss", null,  
    System.Globalization.DateTimeStyles.None, out startTime); 

if (Convert.ToInt32((startTime.Minute.ToString())) > 29) 
{ 
    startTime = DateTime.Parse(string.Format("{0}/{1}/{2} {3}:{4}:{5}", 
     startTime.Month.ToString(), startTime.Day.ToString(), 
     startTime.Year.ToString(), startTime.Hour.ToString(), "00", "00")); 
    startTime = startTime.Add(TimeSpan.Parse("01:00:00")); 
    Console.WriteLine("startTime is :: {0}", 
     startTime.ToString("MM/dd/yyyy HH:mm:ss")); 
} 
else 
{ 
    startTime = DateTime.Parse(string.Format("{0}/{1}/{2} {3}:{4}:{5}", 
     startTime.Month.ToString(), 
     startTime.Day.ToString(), startTime.Year.ToString(), 
     startTime.Hour.ToString(), "00", "00")); 

     Console.WriteLine("startTime is :: {0}", 
     startTime.ToString("MM/dd/yyyy HH:mm:ss")); 
} 
+0

Gracias a todos por sus útiles comentarios y mensajes. :-) –

+0

Sugerencias de Russell_Steen, Hans_Kesting y Hojo también son aceptables. –

+0

posible duplicado de [¿Hay una mejor manera de recortar un DateTime con una precisión específica?] (Http://stackoverflow.com/questions/152774/is-there-a-better-way-to-trim-a-datetime -to-a-specific-precision) –

Respuesta

21

Así como una alternativa:

public static DateTime Round(DateTime dateTime) 
{ 
    var updated = dateTime.AddMinutes(30); 
    return new DateTime(updated.Year, updated.Month, updated.Day, 
         updated.Hour, 0, 0, dateTime.Kind); 
} 
+0

Es posible que desee actualizar su respuesta para incluir la preservación del tipo de fecha y hora; consulte mi publicación http://stackoverflow.com/questions/2499479/how-to-round-off-hours-based-on-minuteshours0-if-min30- hours1-otherwise/2906684 # 2906684 – CrimsonX

+0

@CrimsonX - actualizado. – tvanfosson

+0

muy ingenioso :) :) –

3
DateTime s = DateTime.Now; 
    if (s.Minute > 30) s = s.AddHours(1); //only add hours if > 30 
    if (s.Minute == 30 && s.Second > 0) s = s.AddHours(1); //add precision as needed 
    s = new DateTime(s.Year, s.Month, s.Day, s.Hour, 0, 0); 
+0

Te perdiste los Segundos, no se tocarán. Es mejor crear 1 nuevo DateTime, copiando solo los valores que necesita. –

+0

@Russell, no sé por qué, pero el método AddHours() no funciona ... aunque si la condición se cumple, –

+0

perdió una asignación. tiene que asignar el resultado de addhours a s. typo –

6

¿Qué hay de:

public static DateTime RoundToHours(DateTime input) 
{ 
DateTime dt = new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0); 

    if (input.Minute > 29) 
     return dt.AddHours(1); 
    else 
     return dt; 
} 

No hay necesidad de convertir a la cadena y de vuelta otra vez!

EDIT:
El uso de un input.Hour+1 en el constructor fallará si la hora es de 23. El .AddHours(1) se traducirá correctamente en '0:00' al día siguiente.

+0

ohk .. thanx .. :-) its working. –

1
DateTime dtm = DateTime.Now; 
if (dtm.Minute < 30) 
{ 
    dtm = dtm.AddMinutes(dtm.Minute * -1); 
} 
else 
{  
    dtm = dtm.AddMinutes(60 - dtm.Minute); 
} 
dtm = dtm.AddSeconds(dtm.Second * -1); 
+0

+1 para el código más simple y comprensible :-) –

3

La extensión de Hans Kestings buena respuesta:

public DateTime RoundToHours(DateTime input) 
{ 
     DateTime dt = new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0); 
     return dt.AddHours((int)(input.Minutes/30)); 
} 

no podrían ser necesarias (int) Reparto.

EDIT: Adaptó las correcciones que hizo Hans Kesting en su respuesta.

+0

muchas gracias por alcanzar el requisito. :-) –

22

Si la velocidad es un problema, el siguiente debe ser la forma más rápida:

static DateTime RoundToHour(DateTime dt){ 
    long ticks = dt.Ticks + 18000000000; 
    return new DateTime(ticks - ticks % 36000000000, dt.Kind); 
} 

Es también una manera muy directa y sencilla de hacerlo.

Para explicarlo, una estructura DateTime en realidad no tiene campos que almacenan el año, mes, día, hora, minuto, etc. Almacena un solo valor long, el número de "tics" desde cierta época (Jan 1, 1 AD). Una marca es 100 nanosegundos o una 10,000,000 de segundo.

Cada vez que utilice alguna de las propiedades de fecha/hora, se divide por la constante adecuada.

Aquí, agregamos una constante igual a 30 minutos (30 * 60 * 1e7 = 18000000000 tics), luego restamos el resto después de dividir por una constante igual a una hora (60 * 60 * 1e7 = 36000000000 tics).

+0

¡guau! [15 caracteres] –

+0

gracias por la explicación. Intento implementar esta técnica más cuando sea necesario. –

+0

También puede modificar la declaración de devolución para 'devolver el nuevo DateTime (ticks - ticks% 36000000000, dt.Kind));' para preservar el tipo DateTime del valor DateTime pasado. –

3

Para mejorar algunos de los otros métodos, aquí es un método que también preservará el DateTime tipo:

/// <summary> 
/// Rounds a DateTime to the nearest hour. 
/// </summary> 
/// <param name="dateTime">DateTime to Round</param> 
/// <returns>DateTime rounded to nearest hour</returns> 
public static DateTime RoundToNearestHour(this DateTime dateTime) 
{ 
    dateTime += TimeSpan.FromMinutes(30); 

    return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, 0, 0, dateTime.Kind); 
} 
2

aquí va!

var rounded = date.AddMinutes(30).Date.AddHours(date.AddMinutes(30).Hour); 

Y para aquellos que lo deseen plantas ha

var floored = date.Date.AddHours(date.Hours) 
1

Sobre la base de la solución de P papá, propongo al no codificar ese gran número de garrapatas a una hora. La codificación es mala, ¿verdad? Con esta solución modificada, ahora se puede redondear un momento dado a cualquier número de minutos:

public DateTime RoundToMinutes(DateTime dt, int NrMinutes) 
    { 
     long TicksInNrMinutes = (long)NrMinutes * 60 * 10000000;//1 tick per 100 nanosecond 
     long ticks = dt.Ticks + TicksInNrMinutes/2; 
     return new DateTime(ticks - ticks % TicksInNrMinutes, dt.Kind); 
    } 

lo uso para el redondeo a los 5 minutos más cercanos, por ejemplo, 22:23 se convierte en 22:25.

Hace años utilicé el mismo método para redondear cantidades de dinero al 25 centavo más cercano, p. Ej. $ 22.23 se convierte en $ 22.25. Pero el gerente del proyecto a veces cambió de parecer, pero cambiar el redondeo al 10 o 5 centavos más cercano sería trivial. Así que ahora, de manera similar, no tengo que ponerme nervioso cuando mi jefe de proyecto quiere redondear los tiempos a otra ronda de minutos.

Por lo tanto, este método de redondeo es rápido y flexible.


Mi método ya fue encontrado y publicado en this 2008 SO solution

Cuestiones relacionadas