7

Related to my previous question, but with C#, I need the precise system time including milliseconds.

C# time function has accuracy up to 10 to 15 milliseconds, but not exactly 1 millisecond.

The same is the case with Queue performance counter. Is there any other way to get accuracy up to exact millisecond?

Community
  • 1
  • 1
Badr
  • 10,384
  • 15
  • 70
  • 104

3 Answers3

10

Windows does not want to waste electricity by updating the system clock 1000 times per second, so the default is to only update it 60-100 times per second. If you set the multimedia timer to 1ms, you can get 1ms resolution from the clock, but that's not recommended.

To elaborate more on the electricity savings, what happens when the CPU is idle for a period of time is that it can go into a very-low-power state. Whenever it gets interrupted (e.g. to increment the clock ticks) it has to leave its very-low-power state and use lots of electricity to power the whole CPU to service that interrupt. In other words, the additional power isn't in incrementing the clock ticks, it's in keeping the CPU awake to do it.

Since my laptop uses 10W at idle when the clock frequency is 60Hz and 11W when it's 1000Hz, and I get 300 minutes of battery life, that slower clock is giving me almost 30 extra minutes of battery life!

Gabe
  • 84,912
  • 12
  • 139
  • 238
  • Nitrodist: Yes, that's an explanation of the same problem. – Gabe Jun 29 '10 at 15:40
  • He is talking about kernel tick, a kernel tick is a scheduled hardware (CPU) `timer interrupt`. Windows is far from being good at electricity efficiency though (50% less efficient than android, and 20% less than mac OS), but its no reason to make it worse indeed. Kernel ticks are used to call expired (or coalesced) timers callbacks, re-update thread/process scheduling, and incrementing the global OS tick count. – v.oddou Mar 06 '14 at 07:16
  • How does this answer the question? You are explaining why `DateTime.Now` isn't accurate enough but you're not showing how to get the accuracy up... – Everyone Dec 14 '17 at 03:07
8

You could use this DateTimePrecise class to get a high accuracy time in .NET

UPDATE
The CodeProject link is no longer working. I've pulled the code from archive.org and embedded it here for future reference. This code is included here "as is", exactly the way it was included on the CodeProject page.

DateTimePrecise is as easy to use as DateTime.Now, except that DateTimePrecise.Now is an instance method instead of a static method, so you have to first instantiate a DateTimePrecise.

using System.Diagnostics;

/// 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;
}
Dan Herbert
  • 99,428
  • 48
  • 189
  • 219
  • @Răzvan I've resurrected the code from archive.org and added it to my answer. Thanks for pointing out that it was a dead link. – Dan Herbert Jul 16 '11 at 00:40
  • Watch out when using this code. It will throw an exception for trying to divide by zero. – Dan H Apr 12 '12 at 14:13
  • @Dan H: Could you give an example case in which it throws the exception? – Răzvan Flavius Panda Sep 06 '12 at 14:50
  • can I use this class to compare times from two different applications? i.e. i need not only microsecond precision, but also microsecond accuracy – Oleg Vazhnev May 16 '13 at 11:27
  • @javapowered The time should be *reasonably* accurate. The class uses `Date.UtcNow` as its base, and then counts the time since `UtcNow` using the system's high-precision timer. Because it is derived from `DateTime.UtcNow`, it can never be more accurate than that. You also should check the [`Stopwatch.Frequency`](http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.frequency.aspx) for your hardware to determine that the high-precision functionality is actually working. – Dan Herbert May 16 '13 at 12:32
6

Try System.Diagnostics.Stopwatch for high-resolution timing.

If the installed hardware and operating system support a high-resolution performance counter, then the Stopwatch class uses that counter to measure elapsed time. Otherwise, the Stopwatch class uses the system timer to measure elapsed time.

Try the native DateTime.Ticks for system time accuracy up to one hundred nanoseconds; 1 millisecond = 10000 ticks.

while (true)
{
    System.Threading.Thread.Sleep(1);

    Console.WriteLine("{0} {1}",
        System.DateTime.Now.Ticks,
        System.DateTime.Now.ToString("ss:fff"));
}

PS > .\test.exe
    634134152924322129 52:432
    634134152924332129 52:433
    634134152924342130 52:434
    634134152924352130 52:435
    634134152924362131 52:436
    634134152924372131 52:437
    634134152924382132 52:438
    634134152924392133 52:439
    634134152924402133 52:440
    634134152924412134 52:441
    634134152924422134 52:442
    634134152924432135 52:443
xcud
  • 14,422
  • 3
  • 33
  • 29
  • 3
    He asked for the system time. The Stopwatch just gives an elapsed time. – Gabe Jun 29 '10 at 15:37
  • 3
    Calling `DateTime.Ticks` is no more accurate than `DateTime.Millisecond`. Internally, `DateTime.Millisecond` calls `DateTime.Ticks` – Dan Herbert Jun 30 '10 at 02:02
  • Right. I was just pointing out that according to MSDN and this rough test that it is accurate to at least the millisecond resolution that the questioner is asking for; hence the side by side Console.Output of DateTime as a string alongside Ticks. – xcud Jun 30 '10 at 03:59