2008-09-30 5 views
38

Quelle est la meilleure façon de réduire un objet DateTime à une précision spécifique? Par exemple, si j'ai un DateTime avec une valeur de '2008-09-29 09:41:43', mais je veux seulement que la précision soit à la minute, y a-t-il une meilleure façon de le faire?Existe-t-il un meilleur moyen de réduire un DateTime à une précision spécifique?

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

Ce que je veux vraiment est de rendre variable, de sorte que je puisse mettre sa précision à la seconde, minute, heure ou jour.

Répondre

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

J'aime beaucoup ça et si j'utilisais le framework 3.5, c'est la route que je prendrais, à moins qu'il y ait quelque chose de mieux encore là-bas. Malheureusement, j'utilise le 2.0 et je vais devoir m'en tenir à votre première réponse. Merci! –

+8

Si vous en faites une méthode d'extension à usage général, cela vaut la peine de préserver le DateTimeKind (Unspecified/Utc/Local): return new DateTime (date.Ticks-date.Ticks% roundTicks, date.Kind); – Joe

+0

... ou une ligne qui conserve également la propriété Kind: d = d.AddTicks (- (d.Ticks + 30 * TimeSpan.TicksPerSecond)% TimeSpan.TicksPerMinute); – Joe

4

Vous pouvez utiliser une énumération

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; 
    } 
} 

et étendre au besoin.

+0

Pour les heures et les minutes, je me demande si les minutes et les secondes doivent être arrondies plutôt que 0? – Vivek

+0

Certainement, vous pouvez adapter le code pour arrondir plutôt que de tronquer si vous en avez besoin; Souvent, je trouve que la troncature est plus naturelle car c'est ainsi que les horloges se comportent. – Rikalous

-4

Si vous avez le temps & date un (continue) nombre semblable à time_t, vous pouvez simplement utiliser modulo pour obtenir tous les minutes (60%), les heures, et ainsi de suite. Dans mon expérience, les valeurs semblent être alignées sur le temps réel (modulo 60 se produit à pleine minute), mais ce n'est probablement pas garanti nulle part.

Voici le code pour obtenir ce que vous voulez (avec des sous-deuxième résolution):

/* 
* 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

Lovely C# vous avez là ... – 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

S'il vous plaît supprimer la réponse en double. Je crois qu'une bonne réponse est suffisante – st78

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

code ci-dessus Trimera secondes.

+0

Il ne coupe pas en millisecondes et entraînera un mauvais 'dt'. – Denis

-1

J'aime cette méthode. Quelqu'un a mentionné qu'il était bon de préserver le type de date, etc. Ceci accomplit cela parce qu'il ne fait pas une nouvelle date, il soustrait simplement les ticks restants.

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

Il y a quelques bonnes solutions présentées ici, mais quand je dois le faire, je le fais simplement:

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 

Hope it helps.

+0

ne fonctionne pas, renvoie seulement le jour + 00:00:00 –

+0

@katz: Je suis désolé, mais j'ai testé cette solution lorsque j'ai publié ma réponse et je viens de le tester à nouveau et cela fonctionne parfaitement bien. Êtes-vous sûr de ne pas tester uniquement la première option ci-dessus (trim to day)? Je ne crois pas que tous les appels de méthode TimeSpan.Parse ci-dessus vous retournent 00:00:00.Êtes-vous sûr d'utiliser une variable DIFFERENT (autre que la variable "date" elle-même) pour recevoir les résultats de ces opérations (comme j'ai utilisé "truncDate" dans mon exemple)? Si vous utilisez la variable "date" elle-même, la première opération ci-dessus la tronquera aujourd'hui, compromettant ainsi tous les autres résultats ci-dessous. –

+0

@katz: Utilisez une variable DIFFERENTE (comme "truncDate") et ne faites pas TOUTES les opérations ci-dessus dans l'ordre et ALORS imprimez le résultat. Mon code était juste un exemple, mais CHAQUE opération (chaque ligne de code) devrait être utilisée séparément, selon la précision que vous voulez (jour, heure, minute ou seconde). Par exemple, essayez d'exécuter uniquement la ligne LAST (trim to second), puis imprimez le résultat. –

Questions connexes