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.
-
\$\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– Leonid2012年07月22日 17:58:31 +00:00Commented 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– vgru2012年07月23日 09:27:32 +00:00Commented 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\$Reacher Gilt– Reacher Gilt2012年07月23日 16:29:01 +00:00Commented 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\$Oleg Vazhnev– Oleg Vazhnev2012年07月24日 08:49:07 +00:00Commented 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– vgru2012年07月24日 10:13:49 +00:00Commented Jul 24, 2012 at 10:13
2 Answers 2
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);
}
If you don't need a precise DateTime
, only differences, then don't use DateTime
at all. I think you should work only with TimeSpan
s.
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 TimeSpan
s, this wouldn't be a problem.
-
\$\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\$Oleg Vazhnev– Oleg Vazhnev2012年07月22日 14:09:52 +00:00Commented Jul 22, 2012 at 14:09