tags:

views:

1384

answers:

4

What's the best way to trim a DateTime object to a specific precision? For instance, if I have a DateTime with a value of '2008-09-29 09:41:43' and but I only want it's precision to be to the minute, is there are a better way to do it than this?

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

What I would really want is to make it variable so that I could set its precision to the second, minute, hour, or day.

+4  A: 

You could use an enumeration

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

and expand as required.

Rik Garner
For Hour and Minute, I'm wondering if Minutes and Seconds should be rounded than using 0?
Vivek
Certainly you could adapt the code to round rather than truncate should you need to; often I find truncation feels more natural as that is effectively how clocks behave.
Rik Garner
A: 

If you have time&date as a (continuous) number akin to *time_t*, you can simply use modulo to get full minutes (%60), hours, and so on.

In my experience, the values seem to be aligned with real time (modulo 60 occurs at full minute) but this is most likely not guaranteed anywhere.

Here is code to get what you want (with sub-second resolution):

/*
* 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&gt;
    */
    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
}
akauppi
Lovely C# you have there...
leppie
+1  A: 
    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();
    }
Bartek Szabat
+12  A: 
static class Program
{
    //using extension method:
    static DateTime Trim(this 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(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();
    }

}
Bartek Szabat
I like this very much and if I was using the 3.5 framework, this is the route I would take, unless there's something better still out there. Unfortunately, I'm using 2.0 so I'll have to stick to your first answer. Thanks!
Lloyd Cotten
If you're making it a general-purpose extension method, it's worth preserving the DateTimeKind (Unspecified/Utc/Local):return new DateTime(date.Ticks - date.Ticks % roundTicks, date.Kind);
Joe
... or a one-liner that also preserves the Kind property: d = d.AddTicks(-(d.Ticks + 30*TimeSpan.TicksPerSecond) % TimeSpan.TicksPerMinute);
Joe