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