Есть ли лучший способ обрезать DateTime с определенной точностью?

Какой лучший способ обрезать объект DateTime с определенной точностью? Например, если у меня есть DateTime со значением '2008-09-29 09:41:43', но я хочу только, чтобы точность была на минуту, есть ли лучший способ сделать это, чем это?

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

Мне бы очень хотелось, чтобы он был переменным, чтобы я мог установить его точность во вторую, минуту, час или день.

Ответ 1

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

}

Ответ 2

Вы можете использовать перечисление

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

и развернуть по мере необходимости.

Ответ 3

Есть несколько хороших решений, представленных здесь, но когда мне нужно это сделать, я просто делаю:

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

Надеюсь, что это поможет.

Ответ 4

Мне нравится этот метод. Кто-то упомянул, что было бы хорошо сохранить тип даты и т.д. Это достигается потому, что вам не нужно создавать новый объект DateTime. DateTime правильно клонируется из исходного DateTime и просто вычитает оставшиеся отметки.

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

Ответ 5

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

Ответ 6

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

Выше кода будет обрезать секунды.

Ответ 7

Если у вас есть время & date как (непрерывный) номер, похожий на time_t, вы можете просто использовать modulo для получения полных минут (% 60), часов и т.д.

По моему опыту, значения, похоже, совпадают с реальным временем (по модулю 60 происходит в полную минуту), но это, скорее всего, не гарантируется нигде.

Вот код, чтобы получить то, что вы хотите (с подсезонным разрешением):

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