2008-09-30 11 views
38

¿Cuál es la mejor manera de recortar un objeto DateTime con una precisión específica? Por ejemplo, si tengo un DateTime con un valor de '2008-09-29 09:41:43', pero solo quiero que su precisión sea al minuto, ¿hay alguna forma mejor de hacerlo que esto?¿Hay una mejor manera de recortar un DateTime con una precisión específica?

private static DateTime TrimDateToMinute(DateTime date) 
{ 
    return new DateTime(
     date.Year, 
     date.Month, 
     date.Day, 
     date.Hour, 
     date.Minute, 
     0); 
} 

Lo que realmente me gustaría es para que sea variable, de forma que pudiera establecer su precisión al segundo, minuto, hora o día.

Respuesta

71
static class Program 
{ 
    //using extension method: 
    static DateTime Trim(this DateTime date, long roundTicks) 
    { 
     return new DateTime(date.Ticks - date.Ticks % roundTicks, date.Kind); 
    } 

    //sample usage: 
    static void Main(string[] args) 
    { 
     Console.WriteLine(DateTime.Now); 
     Console.WriteLine(DateTime.Now.Trim(TimeSpan.TicksPerDay)); 
     Console.WriteLine(DateTime.Now.Trim(TimeSpan.TicksPerHour)); 
     Console.WriteLine(DateTime.Now.Trim(TimeSpan.TicksPerMillisecond)); 
     Console.WriteLine(DateTime.Now.Trim(TimeSpan.TicksPerMinute)); 
     Console.WriteLine(DateTime.Now.Trim(TimeSpan.TicksPerSecond)); 
     Console.ReadLine(); 
    } 

} 
+0

Me gusta mucho y si estaba usando el framework 3.5, esta es la ruta que tomaría, a menos que haya algo mejor todavía. Desafortunadamente, estoy usando 2.0, así que tendré que apegarme a tu primera respuesta. ¡Gracias! –

+8

Si lo está convirtiendo en un método de extensión de propósito general, vale la pena preservar DateTimeKind (Unspecified/Utc/Local): return new DateTime (date.Ticks - date.Ticks% roundTicks, date.Kind); – Joe

+0

... o una línea que también conserva la propiedad Tipo: d = d.AddTicks (- (d.Ticks + 30 * TimeSpan.TicksPerSecond)% TimeSpan.TicksPerMinute); – Joe

4

Se podría utilizar una enumeración

public enum DateTimePrecision 
{ 
    Hour, Minute, Second 
} 

public static DateTime TrimDate(DateTime date, DateTimePrecision precision) 
{ 
    switch (precision) 
    { 
    case DateTimePrecision.Hour: 
     return new DateTime(date.Year, date.Month, date.Day, date.Hour, 0, 0); 
    case DateTimePrecision.Minute: 
     return new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, 0); 
    case DateTimePrecision.Second: 
     return new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second); 
    default: 
     break; 
    } 
} 

y ampliar según sea necesario.

+0

Por hora y minuto, me pregunto si los minutos y segundos deben redondearse en lugar de usar 0? – Vivek

+0

Ciertamente, usted podría adaptar el código para redondear en lugar de truncar si lo necesita; a menudo encuentro que el truncado se siente más natural ya que así es como se comportan los relojes. – Rikalous

-4

Si tiene tiempo & fecha como un número (continua) similar a time_t, puede simplemente usar módulo de conseguir minutos completos (60%), hora, y así sucesivamente.

En mi experiencia, los valores parecen estar alineados con el tiempo real (el módulo 60 se produce en el minuto completo), pero es muy probable que esto no esté garantizado en ninguna parte.

Aquí es código para obtener lo que quiere (con menos de un segundo de resolución):

/* 
* Returns millisecond timing (in seconds) for the current time. 
* 
* Note: This function should be called once in single-threaded mode in Win32, 
*  to get it initialized. 
*/ 
double now_secs(void) { 

#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 
    /* 
    * Windows FILETIME values are "100-nanosecond intervals since 
    * January 1, 1601 (UTC)" (MSDN). Well, we'd want Unix Epoch as 
    * the offset and it seems, so would they: 
    * 
    * <http://msdn.microsoft.com/en-us/library/ms724928(VS.85).aspx> 
    */ 
    SYSTEMTIME st; 
    FILETIME ft; 
    ULARGE_INTEGER uli; 
    static ULARGE_INTEGER uli_epoch; // Jan 1st 1970 0:0:0 

    if (uli_epoch.HighPart==0) { 
     st.wYear= 1970; 
     st.wMonth= 1; // Jan 
     st.wDay= 1; 
     st.wHour= st.wMinute= st.wSecond= st.wMilliseconds= 0; 
     // 
     st.wDayOfWeek= 0; // ignored 

     if (!SystemTimeToFileTime(&st, &ft)) 
      FAIL("SystemTimeToFileTime", GetLastError()); 

     uli_epoch.LowPart= ft.dwLowDateTime; 
     uli_epoch.HighPart= ft.dwHighDateTime; 
    } 

    GetSystemTime(&st); // current system date/time in UTC 
    if (!SystemTimeToFileTime(&st, &ft)) 
     FAIL("SystemTimeToFileTime", GetLastError()); 

    uli.LowPart= ft.dwLowDateTime; 
    uli.HighPart= ft.dwHighDateTime; 

    /* 'double' has less accuracy than 64-bit int, but if it were to degrade, 
    * it would do so gracefully. In practise, the integer accuracy is not 
    * of the 100ns class but just 1ms (Windows XP). 
    */ 
    return (double)(uli.QuadPart - uli_epoch.QuadPart)/10000000.0; 
#else 
    struct timeval tv; 
     // { 
     // time_t  tv_sec; /* seconds since Jan. 1, 1970 */ 
     // suseconds_t tv_usec; /* and microseconds */ 
     // }; 

    int rc= gettimeofday(&tv, NULL /*time zone not used any more (in Linux)*/); 
    assert(rc==0); 

    return ((double)tv.tv_sec) + ((tv.tv_usec)/1000)/1000.0; 
#endif 
} 
+3

Precioso C# que tiene allí ... – leppie

0
static DateTime TrimDate(DateTime date, long roundTicks) 
    { 
     return new DateTime(date.Ticks - date.Ticks % roundTicks); 
    } 

    //sample usage: 
    static void Main(string[] args) 
    { 
     Console.WriteLine(DateTime.Now); 
     Console.WriteLine(TrimDate(DateTime.Now, TimeSpan.TicksPerDay)); 
     Console.WriteLine(TrimDate(DateTime.Now, TimeSpan.TicksPerHour)); 
     Console.WriteLine(TrimDate(DateTime.Now, TimeSpan.TicksPerMillisecond)); 
     Console.WriteLine(TrimDate(DateTime.Now, TimeSpan.TicksPerMinute)); 
     Console.WriteLine(TrimDate(DateTime.Now, TimeSpan.TicksPerSecond)); 
     Console.ReadLine(); 
    } 
+0

Por favor, elimine la respuesta duplicada. Creo que una gran respuesta es suficiente – st78

-2
DateTime dt = new DateTime() 
dt = dt.AddSeconds(-dt.Second) 

Por encima de código va a recortar segundos.

+0

No recortará milisegundos y dará como resultado '' dt' malo. – Denis

-1

Me gusta este método. Alguien mencionó que era bueno preservar el Tipo de fecha, etc. Esto lo logra porque no hace una nueva fecha, simplemente resta los tics restantes.

private DateTime FloorToHour(DateTime dt) 
{ 
    return dt.AddTicks(-1 * (dt.Ticks % TimeSpan.TicksPerHour)); 
} 
1

hay algunas buenas soluciones presentadas aquí, pero cuando tengo que hacer esto, yo simplemente:

DateTime truncDate; 
truncDate = date.Date; // trim to day 
truncDate = date.Date + TimeSpan.Parse(string.Format("{0:HH:00:00}", date)); // trim to hour 
truncDate = date.Date + TimeSpan.Parse(string.Format("{0:HH:mm}", date)); // trim to minute 
truncDate = date.Date + TimeSpan.Parse(string.Format("{0:HH:mm:ss}", date)); // trim to second 

espero que ayude.

+0

no funciona, solo devuelve el día + 00:00:00 –

+0

@katz: Lo siento, pero probé esta solución cuando publiqué mi respuesta y la he probado nuevamente y funciona perfectamente bien. ¿Estás seguro de que no estás probando solo la primera opción anterior (recortar al día)? No creo que todas las llamadas anteriores al método TimeSpan.Parse te estén devolviendo 00:00:00.¿Estás seguro de que estás usando una variable DIFERENTE (que no sea la variable "fecha") para recibir los resultados de estas operaciones (como usé "truncDate" en mi ejemplo)? Si utiliza la variable "fecha", la primera operación anterior la truncará al día, lo que compromete el resto de los resultados a continuación. –

+0

@katz: use una variable DIFERENTE (como "truncDate") y no realice TODAS las operaciones de arriba en secuencia y LUEGO imprima el resultado. Mi código era solo un ejemplo, pero CADA operación (cada línea de código) debe usarse por separado, dependiendo de la precisión que desee (día, hora, minuto o segundo). Por ejemplo, intente ejecutar solo la última línea (recorte a segundo) y luego imprima el resultado. –

Cuestiones relacionadas