准确的跟踪时间的方法

时间:2013-10-09 12:25:05

标签: c# time timer duration stopwatch

对于我的应用程序,我要跟踪时间变化,以“平滑”时间变化。

系统时间更改可能有多种原因:

  • 用户更改系统时间
  • 操作系统NTP服务器更新本地时间
  • ...

所以实际上我们有一个“TimeProvider”,它为整个应用程序提供当前时间。

目标是检测是否发生时移并顺利纠正我们的当地时间(例如,如果我们有一个小时的“时间跳跃”,则每秒校正100毫秒,直到完全纠正)。

这基本上是我要提供的时间(请注意,目前我绝对不能顺利改变时间,但不是我目前的问题)

internal class TimeChange : IDisposable
{
    private readonly Timer _timer;
    private readonly Stopwatch _watch = new Stopwatch();
    private DateTime _currentTime;

    public DateTime CurrentTime 
    {
        get { return _currentTime + _watch.Elapsed; }
    }

    public TimeChange()
    {
        _timer = new Timer(1000);
        _timer.Elapsed += OnTimerElapsed;
        _timer.Start();
        _watch.Start();
        _currentTime = DateTime.UtcNow;
    }

    public void Dispose()
    {
        _timer.Stop();
        _timer.Elapsed -= OnTimerElapsed;
    }

    private void OnTimerElapsed(object sender, ElapsedEventArgs e)
    {
        DateTime currentTime = DateTime.UtcNow;
        TimeSpan timeDerivation = currentTime - _currentTime - _watch.Elapsed;
        _watch.Restart();
        _currentTime = currentTime;
        Console.WriteLine("Derivation: " + timeDerivation.TotalMilliseconds + "ms");
    }
}

但是在进行一些测试时,我注意到即使没有在当地时间做任何事情,我也会有所不同。差异不大(<1ms),但仍然存在:

Press enter to stop
Derivation: -0.1367ms
Derivation: 0.9423ms
Derivation: 0.0437ms
Derivation: 0.0617ms
Derivation: 0.0095ms
Derivation: 0.0646ms
Derivation: -0.0149ms

这是1秒的推导,如果我只用1000毫秒替换1000毫秒,我很快就会在1毫秒到0.5毫秒之间推导出来。

所以我的问题(最后:P):

  1. 为什么两个Utc.DateTime之间给了我这么大的差异?它们都是基于时钟刻度号?
  2. 难道没有办法更精确地进行这种时间转换吗?

1 个答案:

答案 0 :(得分:1)

  1. 不,它们都不是基于时钟滴答。 Stopwatch可能是高分辨率或低分辨率。如果低res,那么它使用DateTime.UtcNow underneith。不幸的是,你无法选择是高还是低,所以:

  2. 创建自己的“秒表”,始终使用DateTime.UtcNow underneith。

  3. 修改

    这是(2.)中的一个愚蠢的建议,你显然需要避免DateTime.UtcNow,因为那是你想要纠正的。我建议你看一下使用刻度线,我的意思是1/10000秒,以匹配高分辨率Stopwatch。这是因为TimeSpan仅精确到1/1000秒。

    更详细的第1号:

    Stopwatch使用此方法:

    public static long GetTimestamp()
    {
        if (!Stopwatch.IsHighResolution)
        {
            DateTime utcNow = DateTime.UtcNow;
            return utcNow.Ticks; //There are 10,000 of these ticks in a second
        }
        else
        {
            long num = (long)0;
            SafeNativeMethods.QueryPerformanceCounter(out num);
            return num; //These ticks depend on the processor, and
                        //later will be converted to 1/10000 of a second
        }
    }
    

    但就像我说的那样,IsHighResolution似乎无法设置,而static无论如何都应用于系统范围,所以请自己编写。