Why does timespan totalmilliseconds have the same digits in the integer and decimal parts?
Asked Answered
D

1

9

When calculating the millisecond difference between two DateTime objects I always seem to get a number returned where the decimal part of the number is the same as the integer component of the number. For example: 1235.1235

Why does this happen? Am I doing something wrong? Is this a quirk of the language or a limitation of the DateTime granularity or something?

This can be demonstrated using the following code:

        DateTime then = DateTime.Now;
        Thread.Sleep(1234);
        DateTime now = DateTime.Now;
        TimeSpan taken = now - then;
        string result = taken.TotalMilliseconds.ToString(CultureInfo.InvariantCulture);
        //result = "1235.1235"

As commented by CodesInChaos:

DateTime` isn't accurate to this level of precision: see C# DateTime.Now precision

However - that doesn't quite explain this behavior.

Dismast answered 28/2, 2013 at 15:53 Comment(14)
that likely is just the luck of the draw. also: have a look at the Stopwatch class.Carolynncarolynne
How many times is always?Aude
DateTime.Now at best has millisecond accuracy. In practice it's often just 16ms. I suspect that the fractional part is an artifact of how windows(not .net) represents dates internally.Retrenchment
@ColonelPanic apparently not enough times.Carolynncarolynne
@Colonel (I've seen you around a lot and I've only just got your username >.>)Solidary
@Solidary There is also his superior, General Protection Fault.Retrenchment
@ColonelPanic - I did a run of 1000 times as a testDismast
@Dismast I get the same results with your code- '1234.1234' or if I change it - '152.0152'Aude
For the record, I don't see this behaviour.Solidary
I don't see this behavior either using your code. What version of the .NET Framework are you using? I'm using 4.0.Midshipman
@Mike Payne I'm using .Net 4 client Profile (Debug|x86) running on a Win7 64 bit. (it's just a default WinForms app with a single button in VS2010.)Dismast
And what happens if you sleep for, say, 123456 milliseconds (two minutes and change)?Fulgurating
@JimMischel - for 123456ms I get 123461.3449 - so it doesn't repeat in the same obvious way - but I'm not sure I trust the accuracy of those four decimal places. ;-)Dismast
I do not see this behavior on my machine running .NET 4.5. To tell the truth, I'm kind of surprised that you see it. I wouldn't expect Thread.Sleep to have near-millisecond accuracy.Fulgurating
C
4

There is a technical explanation for this, I cannot otherwise prove that it explains your observation. It certainly doesn't repro on my machine.

For starters you are looking a noise digits, the operating system clock isn't nearly accurate enough to give you sub-millisecond accuracy. So do make sure you never rely on their value to do anything important. If you want to measure an interval with high resolution then you must use Stopwatch instead.

The operating system clock is affected by updates from a time server. Most machines are setup to periodically contact time.windows.com to re-calibrate the clock. This gets rid of clock drift, the machine hardware typically isn't good enough to keep time accurate to better than a second over a month. Low tolerance crystals are expensive and never completely without drift due to temperature and aging effects. And a leap second gets inserted once in a while to keep clocks synchronized with the slowing rotation of the planet. The last one crashed a lot of Linux machines, google "Linux leap second bug" for some fun reading.

What matters here is what happens when your machine gets a new update that requires it to adjust the clock. Windows does not suddenly jump the clock value, that causes major problems with programs that are paying attention to the clock and expect it to consistently increment in predictable amounts.

Instead, it adds a bit at a time with every clock tick increment. In effect making the clock run a bit slower or faster so it will gradually make up the difference and get accurate again. Perhaps you can see where that goes, the extra added microseconds is proportional to the length of the interval. So seeing the interval repeated in the noise digits is plausible.

The only real way to prove this theory is to pinvoke GetSystemTimeAdjustment(). It will return non-zero values when a system time adjustment is in progress. And then pinvoke SetSystemTimeAdjustment() to disable it and observe if that makes a difference in the value you see. Or just wait long enough until the clock has caught up so it doesn't get adjusted anymore.

Condemnatory answered 28/2, 2013 at 19:10 Comment(3)
So if you tested this on a fresh Windows install, GetSystemTimeAdjustment() should return zero and you wouldn't see this behavior?Fulgurating
That's probably the worst time to do it, surely the clock is off big time. Don't plug in the network cable.Condemnatory
Interesting :-) I've checked the TimeAdjustment and it is enabled - the increment is returns as 156001 ticks and doesn't seem to vary. To verify, I'll have to catch it in a non-zero moment to see if the results are different. (I haven't managed to get SetSystemTimeAdjustment to disable the adjustment - so I'll try again later.)Dismast

© 2022 - 2024 — McMap. All rights reserved.