记录时间并在特定时间做某事

时间:2011-03-04 14:54:22

标签: c# datetime

工作缓慢的一天,所以我决定写一个小应用程序来消磨一些时间。它基本上是一个应用程序,用户可以设置时间和动作(关闭,注销等)。

我的问题是,对于我的计划保持时间跟踪的最佳方式是什么?我可以做的一件事是每隔x秒与DateTime.now进行比较,但这会给我一个x秒的误差。

可以/我应该创建一个秒表并让它滴答滴答。当它达到0时,会触发一个事件?

4 个答案:

答案 0 :(得分:3)

您可以创建一个计时器,并将其间隔设置为从现在到应该发生操作的时间量。然后,在OnTick事件处理程序中,执行操作(并停止计时器)。

答案 1 :(得分:1)

或者您可以使用Windows事件调度程序。

答案 2 :(得分:1)

我通常做的是将DateTime.Now与设置的DateTime进行比较,然后将差异作为TimeSpan找到,然后以正确的间隔设置计时器。当计时器用完时,执行正确的操作。

如果你把它提升到一个新的水平,我做了类似的事情,允许设置DayOfTheWeek,时间间隔和时间。并且该服务会确定下一个并且相应地触发。

基本上创建我自己的计划任务Windows服务。

答案 3 :(得分:0)

WinAPI中的CreateWaitableTimer似乎特别适合此任务。我发现分辨率足以满足大多数需求。

您可以使用以下.NET包装器:

public class WaitableTimer: IDisposable
{
    [DllImport("kernel32.dll")]
    private static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetWaitableTimer(SafeWaitHandle hTimer, [In] ref long pDueTime, int lPeriod, IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume);

    [DllImport("kernel32.dll")]
    private static extern bool CancelWaitableTimer(SafeWaitHandle hTimer);

    private SafeWaitHandle _handle;
    private EventWaitHandle _waitHandle;
    private readonly AutoResetEvent _cancelEvent = new AutoResetEvent(false);


    public WaitableTimer()
    {
        _handle = CreateWaitableTimer(IntPtr.Zero, true, "WaitableTimer_" + Guid.NewGuid());
        _waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
        _waitHandle.SafeWaitHandle = _handle;
    }

    public void InterruptWait()
    {
        _cancelEvent.Set();
    }

    public bool WaitUntil(DateTime eventTime)
    {
        long duetime = eventTime.ToFileTime();            

        if (SetWaitableTimer(_handle, ref duetime, 0, IntPtr.Zero, IntPtr.Zero, true))
        {
            return WaitHandle.WaitAny(new[] { _waitHandle, _cancelEvent }) == 0;
        }
        else
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    }

    public void Dispose()
    {
        InterruptWait();
        _handle.Dispose();
    }
}