views:

1949

answers:

5

I have code running in a loop and it's saving state based on the current time. Sometimes this can be just milliseconds apart, but for some reason it seems that DateTime.Now will always return values of at least 10 ms apart even if it's only 2 or 3 ms later. This presents a major problem since the state i'm saving depends on the time it was saved (e.g. recording something)

My test code that returns each value 10 ms apart:

public static void Main()
{
    var dt1 = DateTime.Now;
    System.Threading.Thread.Sleep(2);
    var dt2 = DateTime.Now;

    // On my machine the values will be at least 10 ms apart
    Console.WriteLine("First: {0}, Second: {1}", dt1.Millisecond, dt2.Millisecond);
}

Is there another solution on how to get the accurate current time up to the millisecond ?

Someone suggested to look at the Stopwatch class. Although the Stopwatch class is very accurate it does not tell me the current time, something i need in order to save the state of my program.

A: 

You could use DateTime.Now.Ticks, read the artical on MSDN

"A single tick represents one hundred nanoseconds or one ten-millionth of a second."

Rohan West
Looks promising, I'll check it out.
Where do you think the ticks are coming from? You will still be getting the delay in the datetime measurement, you just have the inaccurate measurement in ticks. All the ticks property returns is a tick representation of the datetime value. you will still have accuracy issues.
RhysC
+2  A: 

IF you take a snap shot of the current time before you do anything, you can just add the stopwatch to the time you stored, no?

x0n
Interesting thought. It's highly performance critical code and I'm not sure using performance counters (Stopwatch internal API) is a good idea. I'll check that out.
+4  A: 

It looks like DateTime is accurate within 16 milliseconds (according to James D. Brock).

Here is some code he wrote for a precision time class:

using System;
using System.Diagnostics;

namespace JamesBrock
{
    /// DateTimePrecise provides a way to get a DateTime that exhibits the
    /// relative precision of
    /// System.Diagnostics.Stopwatch, and the absolute accuracy of DateTime.Now.
    public class DateTimePrecise
    {
        /// Creates a new instance of DateTimePrecise.
        /// A large value of synchronizePeriodSeconds may cause arithmetic overthrow
        /// exceptions to be thrown. A small value may cause the time to be unstable.
        /// A good value is 10.
        /// synchronizePeriodSeconds = The number of seconds after which the
        /// DateTimePrecise will synchronize itself with the system clock.
        public DateTimePrecise(long synchronizePeriodSeconds)
        {
            Stopwatch = Stopwatch.StartNew();
            this.Stopwatch.Start();

            DateTime t = DateTime.UtcNow;
            _immutable = new DateTimePreciseSafeImmutable(t, t, Stopwatch.ElapsedTicks,
                Stopwatch.Frequency);

            _synchronizePeriodSeconds = synchronizePeriodSeconds;
            _synchronizePeriodStopwatchTicks = synchronizePeriodSeconds *
                Stopwatch.Frequency;
            _synchronizePeriodClockTicks = synchronizePeriodSeconds *
                _clockTickFrequency;
        }

        /// Returns the current date and time, just like DateTime.UtcNow.
        public DateTime UtcNow
        {
            get
            {
                long s = this.Stopwatch.ElapsedTicks;
                DateTimePreciseSafeImmutable immutable = _immutable;

                if (s < immutable._s_observed + _synchronizePeriodStopwatchTicks)
                {
                    return immutable._t_base.AddTicks(((
                        s - immutable._s_observed) * _clockTickFrequency) / (
                        immutable._stopWatchFrequency));
                }
                else
                {
                    DateTime t = DateTime.UtcNow;

                    DateTime t_base_new = immutable._t_base.AddTicks(((
                        s - immutable._s_observed) * _clockTickFrequency) / (
                        immutable._stopWatchFrequency));

                    _immutable = new DateTimePreciseSafeImmutable(
                        t,
                        t_base_new,
                        s,
                        ((s - immutable._s_observed) * _clockTickFrequency * 2)
                        /
                        (t.Ticks - immutable._t_observed.Ticks + t.Ticks +
                            t.Ticks - t_base_new.Ticks - immutable._t_observed.Ticks)
                    );

                    return t_base_new;
                }
            }
        }

        /// Returns the current date and time, just like DateTime.Now.
        public DateTime Now
        {
            get
            {
                return this.UtcNow.ToLocalTime();
            }
        }

        /// The internal System.Diagnostics.Stopwatch used by this instance.
        public Stopwatch Stopwatch;

        private long _synchronizePeriodStopwatchTicks; 
        private long _synchronizePeriodSeconds;
        private long _synchronizePeriodClockTicks;
        private const long _clockTickFrequency = 10000000;
        private DateTimePreciseSafeImmutable _immutable;
    }

    internal sealed class DateTimePreciseSafeImmutable
    {
        internal DateTimePreciseSafeImmutable(DateTime t_observed, DateTime t_base,
             long s_observed, long stopWatchFrequency)
        {
            _t_observed = t_observed;
            _t_base = t_base;
            _s_observed = s_observed;
            _stopWatchFrequency = stopWatchFrequency;
        }
        internal readonly DateTime _t_observed;
        internal readonly DateTime _t_base;
        internal readonly long _s_observed;
        internal readonly long _stopWatchFrequency;
    }
}

Here is a link to the original article: http://www.codeproject.com/KB/cs/DateTimePrecise.aspx?display=Print

Jason Stevenson
A: 

You should ask yourself if you really need accurate time, or just close enough time plus an increasing integer.

You can do good things by getting now() just after a wait event such as a mutex, select, poll, WaitFor*, etc, and then adding a serial number to that, perhaps in the nanosecond range or wherever there is room.

You can also use the rdtsc machine instruction (some libraries provide an API wrapper for this, not sure about doing this in C# or Java) to get cheap time from the CPU and combine that with time from now(). The problem with rdtsc is that on systems with speed scaling you can never be quite sure what its going to do. It also wraps around fairly quickly.

Zan Lynx
My problem is that I need to replay the saved state. So if i save two states 5 ms apart I need to be able to replay them 5 ms apart. Just knowing the order is not enough.
I don't know the problem you are trying to solve, but you may be trying too hard. Just getting the order right within 10 ms granularity may be enough.
Zan Lynx
+2  A: 

The problem with DateTime when dealing with milliseconds isn't due to the DateTime class at all, but rather, has to do with CPU ticks and thread slices. Essentially, when an operation is paused by the scheduler to allow other threads to execute, it must wait at a minimum of 1 time slice before resuming which is around 15ms on modern Windows OSes. Therefore, any attempt to pause for less than this 15ms precision will lead to unexpected results.

Chris
Erm, the problem is because DateTime.Now has a resolution of 10 milliseconds... See http://msdn.microsoft.com/en-us/library/system.datetime.now.aspx
configurator
And where do you think that 10 millisecond restriction comes from? Hint: It's not arbitrary.
Chris