Is there a better way in C# to round a DateTime to the nearest 5 seconds?

后端 未结 7 1018
半阙折子戏
半阙折子戏 2020-12-09 04:33

I want to round a DateTime to the nearest 5 seconds. This is the way I\'m currently doing it but I was wondering if there was a better or more concise way?

         


        
相关标签:
7条回答
  • 2020-12-09 04:53

    (Sorry for the resurrection; I recognize it's an old and answered question - just adding some extra code for Google's sake.)

    I started with JayMcClellan's answer, but then I wanted it to be more generic, rounding to arbitrary intervals (not just 5 seconds). So I ended up leaving Jay's method for one that uses Math.Round on ticks and put it into an extension method that can take arbitrary intervals and also offers the option of changing the rounding logic (banker's rounding versus away-from-zero). I'm posting here in case this is helpful to someone else as well:

        public static TimeSpan Round(this TimeSpan time, TimeSpan roundingInterval, MidpointRounding roundingType) {
            return new TimeSpan(
                Convert.ToInt64(Math.Round(
                    time.Ticks / (decimal)roundingInterval.Ticks,
                    roundingType
                )) * roundingInterval.Ticks
            );
        }
    
        public static TimeSpan Round(this TimeSpan time, TimeSpan roundingInterval) {
            return Round(time, roundingInterval, MidpointRounding.ToEven);
        }
    
        public static DateTime Round(this DateTime datetime, TimeSpan roundingInterval) {
            return new DateTime((datetime - DateTime.MinValue).Round(roundingInterval).Ticks);
        }
    

    It won't win any awards for bare efficiency, but I find it easy to read and intuitive to use. Example usage:

    new DateTime(2010, 11, 4, 10, 28, 27).Round(TimeSpan.FromMinutes(1)); // rounds to 2010.11.04 10:28:00
    new DateTime(2010, 11, 4, 13, 28, 27).Round(TimeSpan.FromDays(1)); // rounds to 2010.11.05 00:00
    new TimeSpan(0, 2, 26).Round(TimeSpan.FromSeconds(5)); // rounds to 00:02:25
    new TimeSpan(3, 34, 0).Round(TimeSpan.FromMinutes(37); // rounds to 03:42:00...for all your round-to-37-minute needs
    
    0 讨论(0)
  • 2020-12-09 04:56

    How about this (blending a few answers together)? I think it conveys the meaning well and should handle the edge cases (rounding to the next minute) elegantly due to AddSeconds.

    // truncate to multiple of 5
    int second = 5 * (int) (now.Second / 5);
    DateTime dt = new DateTime(..., second);
    
    // round-up if necessary
    if (now.Second % 5 > 2.5)
    {
        dt = dt.AddSeconds(5);
    }
    

    The Ticks approach as shown by Jay is more concise, but may be a bit less readable. If you use that approach, at least reference TimeSpan.TicksPerSecond.

    0 讨论(0)
  • 2020-12-09 05:01

    I couldn't recognize the difference between C# and a bar of soap (well, I couldn't when I originally wrote this answer, things have changed quite a bit in the years since) but, if you're looking for a more concise solution, I would just put the whole thing in a function - there's little that will be more concise in your code than a simple call to said function:

    DateTime rounded = roundTo5Secs (DateTime.Now);
    

    Then you can put whatever you want in the function and just document how it works, such as (assuming these are all integer operations):

    secBase = now.Second / 5;
    secExtra = now.Second % 5;
    if (secExtra > 2) {
        return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute,
            secBase + 5);
    }
    return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute,
        secBase);
    

    You may also need some extra checks if secBase goes to 60 (unless C# DateTime objects are smart enough to bump up the minute (and hour if minute goes to 60, and so on).

    0 讨论(0)
  • 2020-12-09 05:07

    Like you mentioned, it's fairly easy to truncate. So, just add 2.5 seconds, then truncate down.

    0 讨论(0)
  • 2020-12-09 05:07

    I can't think of a better way, although I would probably factor out the round method:

    static int Round(int n, int r)
    {
        if ((n % r) <= r / 2)
        {
            return n - (n % r); 
        }
        return n + (r - (n % r));
    }
    

    Also, % returns an int, so comparing it to 2.5 strikes me as a little odd, even though it is correct. I'd use >= 3.

    0 讨论(0)
  • 2020-12-09 05:10

    Technically, you can never correctly round to an odd interval given only seconds.

    2, 4, 6, 8, 10 <-- are no problem

    If you are 'distributing' times in intervals and if the jitter is low, truncation is a lot more tractable.

    If you can pass milliseconds and round at a 500mS mark, you will be able to to odd seconds and also slash the effect of jitter way down or eliminate it entirely.

    0 讨论(0)
提交回复
热议问题