4

I'm hitting something here which is very odd but I'm not sure whether it's me knowing the TimeSpan APIs wrong. The following prints out false and I'm not sure why:

var foo = TimeSpan.FromMilliseconds(123.34d);
var bar = TimeSpan.FromMilliseconds(123.33d);
Console.WriteLine(foo > bar);

The following prints true:

var foo = TimeSpan.FromMilliseconds(123.34d);
var bar = TimeSpan.FromMilliseconds(123.33d);
Console.WriteLine(foo == bar);

Doesn't TimeSpan.FromMilliseconds take millisecond precision into account while doing the comparison?

tugberk
  • 57,477
  • 67
  • 243
  • 335
  • I executed both in Linqpad and they both dumped to the console as 00:00:00.1230000. – Stephen Kennedy Oct 26 '14 at 10:15
  • 1
    What are the real values when you look at one of the vars in a debugger? – lboshuizen Oct 26 '14 at 10:15
  • 1
    possible duplicate of [TimeSpan FromMilliseconds strange implementation?](http://stackoverflow.com/questions/5450439/timespan-frommilliseconds-strange-implementation) – Stephen Kennedy Oct 26 '14 at 10:16
  • 2
    From [MSDN](http://msdn.microsoft.com/en-us/library/system.timespan.frommilliseconds(v=vs.110).aspx) web site, in remarks section `The value parameter is converted to ticks, and that number of ticks is used to initialize the new TimeSpan. Therefore, value will only be considered accurate to the nearest millisecond` – Michael Oct 26 '14 at 10:17
  • 1
    Value is rounded. Check http://stackoverflow.com/questions/4672359/why-does-timespan-fromsecondsdouble-round-to-milliseconds – Polhovskiy Oct 26 '14 at 10:20

4 Answers4

5

TimeSpan simply rounds the number of milliseconds that you pass it, so both 123.33 and 123.34 end up representing a timespan of 123 milliseconds. 123.5 would be rounded up to 123 milliseconds.

If you need better precision, do the math with the ticks yourself:

var foo = TimeSpan.FromTicks((long)(123.34*TimeSpan.TicksPerMillisecond));
var bar = TimeSpan.FromTicks((long)(123.33*TimeSpan.TicksPerMillisecond));
Console.WriteLine(foo > bar);

Now your program produces True (demo).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

According to the API documentation http://msdn.microsoft.com/en-us/library/system.timespan.frommilliseconds(v=vs.110).aspx the method TimeSpan.FromMilliSeconds(double d) takes any double value but only respects values up to one digit after the comma since the double is converted into ticks before it is used within the TimeSpan struct.

The value parameter is converted to ticks, and that number of ticks is used to initialize the new TimeSpan. Therefore, value will only be considered accurate to the nearest millisecond. Note that, because of the loss of precision of the Double data type, this conversion can generate an OverflowException for values that are near to but still in the range of either MinValue or MaxValue.

This is also emphasized by the examples on that site:

GenTimeSpanFromMillisec( 1 );
GenTimeSpanFromMillisec( 1.5 );
GenTimeSpanFromMillisec( 12345.6 );
GenTimeSpanFromMillisec( 123456789.8 );
GenTimeSpanFromMillisec( 1234567898765.4 );
GenTimeSpanFromMillisec( 1000 );
GenTimeSpanFromMillisec( 60000 );
GenTimeSpanFromMillisec( 3600000 );
GenTimeSpanFromMillisec( 86400000 );
GenTimeSpanFromMillisec( 1801220200 );

marc wellman
  • 5,808
  • 5
  • 32
  • 59
0

Timespan accepts a floating point as a parameter for milliseconds but ignores the decimals.

Makes sense, as timespan has no notion of sub-milliseconds; it's the smallest unit.

lboshuizen
  • 2,746
  • 17
  • 20
0

Its an issue with precision:

var fooba = TimeSpan.FromMilliseconds(123.36d);
var foob = TimeSpan.FromMilliseconds(123.35d);
var foo = TimeSpan.FromMilliseconds(123.34d);
var bar = TimeSpan.FromMilliseconds(123.33d);
Console.WriteLine(fooba + " > " + foob + "?: " + (fooba > foob));
Console.WriteLine(foob + " > " + foo + "?: " + (foob > foo));
Console.WriteLine(foo + " > " + bar + "?: " + (foo > bar));
Console.WriteLine(fooba + " == " + foob + "?: " + (fooba == foob));
Console.WriteLine(foob + " == " + foo + "?: " + (foob == foo));
Console.WriteLine(foo + " == " + bar + "?: " + (foo == bar));

00:00:00.1230000 > 00:00:00.1230000?: False
00:00:00.1230000 > 00:00:00.1230000?: False
00:00:00.1230000 > 00:00:00.1230000?: False
00:00:00.1230000 == 00:00:00.1230000?: True
00:00:00.1230000 == 00:00:00.1230000?: True
00:00:00.1230000 == 00:00:00.1230000?: True
HDL_CinC_Dragon
  • 194
  • 1
  • 8