views:

128

answers:

4
DateTime.Now.AddMilliseconds(1.5); // adds 2 milliseconds

What on earth were they thinking here? It strikes me as horrendously bad practice to create a method that takes a double if it doesn't handle fractional values. Why didn't they implement this with a call to AddTicks and handle the fraction properly? Or at least take an int, so it's transparent to callers?

I'm guessing there must be a good reason why they implemented it this way, but I can't think of what it could be. Can anyone offer any insight?

EDIT: just to further emphasise the point:

AddSeconds(1.5); // Adds 1500 milliseconds
A: 

From MSDN:

The milliseconds value is rounded to the nearest integer before it is added to the specified DateTime.

As DateTime can't resolve anything less then milliseconds, adding fractional milliseconds would also be the wrong thing to do.

I would say they have made a compromise - it is better then throwing an exception and would work as most programmers would expect.

Oded
Huh? I don't understand, what do you mean DateTime can't resolve anything less than milliseconds? And the MSDN quote doesn't explain *why* they implemented it this way. The behaviour of a well implemented method should be obvious without having to read through the minutae of the documentation.
fearofawhackplanet
-1 This does not answer the question, which was *why* the function takes a double arg, only to round it to int.
sleske
It's true that this is documented, but it doesn't answer why to have an overload that takes a `double` when in fact only `int` is accepted. And `DateTime` uses a higher precision than ms: "Time values are measured in 100-nanosecond units called ticks", see http://msdn.microsoft.com/en-us/library/system.datetime.aspx
0xA3
+2  A: 

It does seem rather bizarre. My only thought is that perhaps they felt it better to round to the nearest millisecond, rather than risk the caller truncating a double to an int. Yes, this is a rather feeble explanation. Sorry.

Marcelo Cantos
Especially seeing how if they were just going to truncate it to an int, they should have it passed as such and force the developer to explicitly cast their values.
Grant Peters
+1  A: 

DateTime and TimeSpan do some rounding. But knowing Ticks are 100ns intervals you can work around this:

var now = DateTime.Now;
var result = now + TimeSpan.FromTicks(10000 * 1.5);

(There are 10,000 100ns intervals in 1ms.)

EDIT: Corrected this, DateTime stores count of *100*ns internals (not 10ns).

Richard
+2  A: 

It is a compromise, not an entirely unreasonable one. The passed argument has to be rounded to deal with the resolution of DateTime. Rounding to the accuracy of a tick (100 nanoseconds) is a problem. Double doesn't have enough significant digits to be able to span the full range of possible dates. 10000 years x 365 x 24 x 3600 x 1000 x 10000 = 3E18, double has only 15 significant digits. There is no problem by rounding to a millisecond, 3E14 is just good enough (what are the odds?)

The workaround is simple, just use AddTicks(1.5 * 10000).

Hans Passant
Nice explanation! Though if I were the MS team on this, I would have opted for triming the top of the full range of values, simply because not too many people will worry about values that high and when they do, they should be aware of the problems faced with the lack of significant digits and just go for 64 bit int instead (or if necessary, 128 bit).
Grant Peters
Not sure, the Y10K problem looks difficult to solve to me :)
Hans Passant
good points. but then still, why use double in the param?
fearofawhackplanet
Guessing: it was an interop problem. The alternative is a long but that isn't well supported by legacy code. Like COM.
Hans Passant