4
\$\begingroup\$

Answer in this question contains DateTimePrecise class that should return current date with millisecond precision. But class is pretty bug and complicated. So I wrote my own version which seems work fine. If you see any problems with my code?

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
class DateTimePrecise
{
    private long startTick;
    private Stopwatch sw;

    public DateTimePrecise()
    {
        startTick = DateTime.Now.Ticks;
        sw = Stopwatch.StartNew();
    }

    public DateTime CurDateTime()
    {
        return new DateTime(startTick + sw.ElapsedTicks);
    }

}
}

I understand that my version is not accurate, meaning that actual system time may be less or more up to several milliseconds (±16 ms likely). But my version is still precise meaning that couple of measurements will defer at exactly spent milliseconds. And that's exactly what I need. I need precise but not necessary accurate clock because I only need to compare values between each other and I don't need exact current time up to milliseconds.

\$\endgroup\$
8
  • \$\begingroup\$ You now need to be able to compare this instance to another or to any object, etc. so there are things like IComparable, IEquitable, ... \$\endgroup\$
    – Leonid
    Jul 22, 2012 at 17:58
  • \$\begingroup\$ Reading your comment below, one thing doesn't make sense: what does current time have to do with plotting a graph? \$\endgroup\$
    – vgru
    Jul 23, 2012 at 9:27
  • 1
    \$\begingroup\$ Microsoft has an example of using the high-resolution timer. This timer provides accuracy to the millisecond. A sample implementation is available here: msdn.microsoft.com/en-us/library/aa964692(v=vs.85).aspx \$\endgroup\$ Jul 23, 2012 at 16:29
  • \$\begingroup\$ @Groo because I need to see current time so I can go to trading terminal and to compare what I see on graph with what I see in terminal. \$\endgroup\$ Jul 24, 2012 at 8:49
  • 1
    \$\begingroup\$ You should describe your actual use case to get better suggestions, because I am pretty sure that this approach won't solve your problem. \$\endgroup\$
    – vgru
    Jul 24, 2012 at 10:13

2 Answers 2

1
\$\begingroup\$

You can't have a reliable 1 ms resolution timer like that.

Anyone who knows otherwise should paste a minimal code that runs for full 5 minutes, and outputs an array of ~ 5*60*1000 ms ticks with a max diff of 2.


Well, that being said, please consult my timer class and let me know if it's helpful for you:

public class TimerWrapper : ITimer
{
    #region DLL IMPORT
    [DllImport("WinMM.dll", SetLastError = true)]
    private static extern uint timeSetEvent(int msDelay, int msResolution,
                TimerEventHandler handler, ref int userCtx, int eventType);

    [DllImport("WinMM.dll", SetLastError = true)]
    static extern uint timeKillEvent(uint timerEventId);

    [DllImport("Winmm.dll")]
    private static extern int timeGetTime();
    #endregion

    public event Action<int> __Tick;
    public event Action __Stopped;

    public delegate void TimerEventHandler(uint id, uint msg, ref int userCtx,
        int rsv1, int rsv2);

    public void Stop()
    {
        timeKillEvent(m_fastTimer);
        InvokeStopped();
    }

    public void Start(int interval, int timeout)
    {
        m_res = 0;
        m_count = 0;
        _startCount = timeGetTime();
        m_maxCount = timeout * 1000 / interval;
        m_interval = interval;
        int myData = 0; // dummy data
        _thandler = new TimerEventHandler(tickHandler);
        m_fastTimer = timeSetEvent(interval, interval, _thandler,
            ref myData, 1); // type=periodic
    }

    private void InvokeTick(int t)
    {
        if (__Tick != null)
        {
            __Tick(t);
        }
    }

    private void InvokeStopped()
    {
        if (__Stopped != null)
        {
            __Stopped();
        }
    }

    private long m_maxCount;
    private int m_interval;
    private uint m_fastTimer;
    private long m_count;
    private int _startCount;
    private int _maxTimerTTL = 1000;    // ms
    private int m_res;
    private TimerEventHandler _thandler;

    private bool IsInfinite { get { return m_maxCount < 0; } }
    private bool IsRestarted { get { return m_interval <= 100 && m_interval >= 5; } }

    private void tickHandler(uint id, uint msg, ref int userCtx, int rsv1, int rsv2)
    {
        int span = timeGetTime() - _startCount;
        InvokeTick(span + m_res);

        if (m_count++ >= m_maxCount && !IsInfinite)
        {
            Stop();
        }
        else if (IsRestarted && span > _maxTimerTTL)
        {
            m_res += span;
            RestartTimer();
            _startCount = timeGetTime();
        }
    }

    private void RestartTimer()
    {
        int myData = 0; // dummy data
        timeKillEvent(m_fastTimer);
        m_fastTimer = timeSetEvent(m_interval, m_interval, new TimerEventHandler(tickHandler), ref myData, 1);  // type=periodic
    }
}

Interface:

public interface ITimer
{
    event Action<int> __Tick;
    event Action __Stopped;
    void Start(int interval, int timeout);
    void Stop();
}

Usage:

public static void Main()
{
    var barrier = new ManualResetEvent(false);
    var list = new List<int>();
    ITimer timer = new TimerWrapper();
    timer.__Tick += new Action<int> ( (i) => list.Add(i) );
    timer.__Stopped += new Action ( () => barrier.Set() );
    timer.Start(1, 5 * 60);
    barrier.WaitOne();
    foreach(var v in list)
        Console.WriteLine(v);
}
\$\endgroup\$
1
\$\begingroup\$

If you don't need a precise DateTime, only differences, then don't use DateTime at all. I think you should work only with TimeSpans.

This will avoid confusion, because with your class, it looks like DateTimePrecise .CurDateTime() is better than DateTime.Now, even when used once. If you only used TimeSpans, this wouldn't be a problem.

\$\endgroup\$
1
  • \$\begingroup\$ i'm using this datetimes to plot graphics in matlab. so I need "about" true value (16ms precision is ok) so I can understand where I am on the graphic. but I also need to distinguish dots close to each other because i do analyze trades that close to each other (sometimes i do trade every 1 ms) \$\endgroup\$ Jul 22, 2012 at 14:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.