Can you round a .NET TimeSpan object?

后端 未结 10 863
渐次进展
渐次进展 2020-12-03 03:01

Can you round a .NET TimeSpan object?

I have a Timespan value of: 00:00:00.6193789

Is there a simple way to keep it a TimeSp

相关标签:
10条回答
  • 2020-12-03 03:26

    Yet another way to round milliseconds to the nearest second.

    private const long TicksPer1000Milliseconds = 1000 * TimeSpan.TicksPerMillisecond;
    
    // Round milliseconds to nearest second
    // To round up, add the sub-second ticks required to reach the next second
    // To round down, subtract the sub-second ticks
    elapsedTime = new TimeSpan(elapsedTime.Ticks + (elapsedTime.Milliseconds >= 500 ? TicksPer1000Milliseconds - (elapsedTime.Ticks % TicksPer1000Milliseconds) : -(elapsedTime.Ticks % TicksPer1000Milliseconds)));
    
    0 讨论(0)
  • 2020-12-03 03:28

    Here is a nice Extention-Method:

        public static TimeSpan RoundToSeconds(this TimeSpan timespan, int seconds = 1)
        {
            long offset = (timespan.Ticks >= 0) ? TimeSpan.TicksPerSecond / 2 : TimeSpan.TicksPerSecond / -2;
            return TimeSpan.FromTicks((timespan.Ticks + offset) / TimeSpan.TicksPerSecond * TimeSpan.TicksPerSecond);
        }
    

    And here are some Examples:

    DateTime dt1 = DateTime.Now.RoundToSeconds();  // round to full seconds
    DateTime dt2 = DateTime.Now.RoundToSeconds(5 * 60);  // round to full 5 minutes
    
    0 讨论(0)
  • 2020-12-03 03:30
    new TimeSpan(tmspan.Hours, tmspan.Minutes, tmspan.Seconds, (int)Math.Round(Convert.ToDouble(tmspan.Milliseconds / 10)));
    
    0 讨论(0)
  • 2020-12-03 03:31

    TimeSpan is little more than a wrapper around the 'Ticks' member. It's pretty easy to create a new TimeSpan from a rounded version of another TimeSpan's Ticks.

    TimeSpan t1 = new TimeSpan(2345678);
    Console.WriteLine(t1);
    TimeSpan t2 = new TimeSpan(t1.Ticks - (t1.Ticks % 100000));
    Console.WriteLine(t2);
    

    Gives:

    00:00:00.2345678
    00:00:00.2300000
    
    0 讨论(0)
  • 2020-12-03 03:35

    My solution:

        static TimeSpan RoundToSec(TimeSpan ts)
        {
            return TimeSpan.FromSeconds((int)(ts.TotalSeconds));
        }
    
    0 讨论(0)
  • 2020-12-03 03:42

    Simplest one-liner if you are rounding to whole seconds:

    public static TimeSpan RoundSeconds( TimeSpan span ) {
        return TimeSpan.FromSeconds( Math.Round( span.TotalSeconds ) );
    }
    

    To round to up to 3 digits (e.g. tenths, hundredths of second, or milliseconds:

    public static TimeSpan RoundSeconds( TimeSpan span, int nDigits ) {
        // TimeSpan.FromSeconds rounds to nearest millisecond, so nDigits should be 3 or less - won't get good answer beyond 3 digits.
        Debug.Assert( nDigits <= 3 );
        return TimeSpan.FromSeconds( Math.Round( span.TotalSeconds, nDigits ) );
    }
    

    For more than 3 digits, its slightly more complex - but still a one-liner. This can also be used for 3 or less digits - it is a replacement for the version shown above:

    public static TimeSpan RoundSeconds( TimeSpan span, int nDigits ) {
        return TimeSpan.FromTicks( (long)( Math.Round( span.TotalSeconds, nDigits ) * TimeSpan.TicksPerSecond) );
    }
    

    If you want a string (according to a comment, this technique only works up to 7 digits):

    public static string RoundSecondsAsString( TimeSpan span, int nDigits ) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < nDigits; i++)
            sb.Append( "f" );
        return span.ToString( @"hh\:mm\:ss\." + sb );
    }
    

    For time of day, as hours and minutes, rounded:

    public static TimeSpan RoundMinutes(TimeSpan span)
        {
            return TimeSpan.FromMinutes(Math.Round(span.TotalMinutes));
        }
    

    If you have a DateTime, and want to extract time of day rounded:

    DateTime dt = DateTime.Now();
    TimeSpan hhmm = RoundMinutes(dt.TimeOfDay);
    

    To display rounded 24 hour time:

    string hhmmStr = RoundMinutes(dt.TimeOfDay).ToString(@"hh\:mm");
    

    To display time of day in current culture:

    string hhmmStr = new DateTime().Add(RoundMinutes(dt.TimeOfDay)).ToShortTimeString();
    

    Credits:

    cc1960's answer shows use of FromSeconds, but he rounded to whole seconds. My answer generalizes to specified number of digits.

    Ed's answer suggests using a format string, and includes a link to the formatting document.

    Chris Marisic shows how to apply ToShortTimeString to a TimeSpan (by first converting to a DateTime).


    To round to multiple of some other unit, such as 1/30 second:

        // Rounds span to multiple of "unitInSeconds".
        // NOTE: This will be close to the requested multiple,
        // but is not exact when unit cannot be exactly represented by a double.
        // e.g. "unitInSeconds = 1/30" isn't EXACTLY 1/30,
        // so the returned value won't be exactly a multiple of 1/30.
        public static double RoundMultipleAsSeconds( TimeSpan span, double unitInSeconds )
        {
            return unitInSeconds * Math.Round( span.TotalSeconds / unitInSeconds );
        }
    
        public static TimeSpan RoundMultipleAsTimeSpan( TimeSpan span, double unitInSeconds )
        {
            return TimeSpan.FromTicks( (long)(RoundMultipleAsSeconds( span, unitInSeconds ) * TimeSpan.TicksPerSecond) );
    
            // IF USE THIS: TimeSpan.FromSeconds rounds the result to nearest millisecond.
            //return TimeSpan.FromSeconds( RoundMultipleAsSeconds( span, unitInSeconds ) );
        }
    
        // Rounds "span / n".
        // NOTE: This version might be a hair closer in some cases,
        // but probably not enough to matter, and can only represent units that are "1 / N" seconds.
        public static double RoundOneOverNAsSeconds( TimeSpan span, double n )
        {
            return Math.Round( span.TotalSeconds * n ) / n;
        }
    
        public static TimeSpan RoundOneOverNAsTimeSpan( TimeSpan span, double n )
        {
            return TimeSpan.FromTicks( (long)(RoundOneOverNAsSeconds( span, n ) * TimeSpan.TicksPerSecond) );
    
            // IF USE THIS: TimeSpan.FromSeconds rounds the result to nearest millisecond.
            //return TimeSpan.FromSeconds( RoundOneOverNAsSeconds( span, n ) );
        }
    

    To use one of these to round to multiples of 1/30 second:

        private void Test()
        {
            long ticks = (long) (987.654321 * TimeSpan.TicksPerSecond);
            TimeSpan span = TimeSpan.FromTicks( ticks );
            TestRound( span, 30 );
            TestRound( TimeSpan.FromSeconds( 987 ), 30 );
        }
    
        private static void TestRound(TimeSpan span, int n)
        {
            var answer1 = RoundMultipleAsSeconds( span, 1.0 / n );
            var answer2 = RoundMultipleAsTimeSpan( span, 1.0 / n );
            var answer3 = RoundOneOverNAsSeconds( span, n );
            var answer4 = RoundOneOverNAsTimeSpan( span, n );
        }
    

    Results viewed in debugger:

    // for 987.654321 seconds:
        answer1 987.66666666666663  double
        answer2 {00:16:27.6666666}  System.TimeSpan
        answer3 987.66666666666663  double
        answer4 {00:16:27.6666666}  System.TimeSpan
    
    // for 987 seconds:
        answer1 987 double
        answer2 {00:16:27}  System.TimeSpan
        answer3 987 double
        answer4 {00:16:27}  System.TimeSpan
    
    0 讨论(0)
提交回复
热议问题