到目前为止,我用来DateTime.Now
获取时间戳,但是我注意到如果你DateTime.Now
在一个循环中打印,你会看到它以大约的离散跳跃增量.15毫秒 但对于我的应用程序中的某些情况,我需要获得最准确的时间戳,最好是精确到tick(= 100 ns).有任何想法吗?
更新:
显然,StopWatch
/ QueryPerformanceCounter
是要走的路,但它只能用于测量时间,因此我考虑DateTime.Now
在应用程序启动时调用,然后StopWatch
运行,然后只将经过的时间从StopWatch
返回的初始值中添加DateTime.Now
.至少那应该给我准确的相对时间戳,对吧?你怎么看待(黑客)?
注意:
StopWatch.ElapsedTicks
不同于StopWatch.Elapsed.Ticks
!我使用前者假设1 tick = 100 ns,但在这种情况下1 tick = 1/StopWatch.Frequency
.所以要获得相当于DateTime使用的刻度StopWatch.Elapsed.Ticks
.我刚刚学到了这个困难的方法.
笔记2:
使用StopWatch方法,我注意到它与实时不同步.大约10个小时后,它提前5秒.所以我想我们必须每隔X左右重新同步一次,其中X可能是1小时30分钟,15分钟等等.我不确定重新同步的最佳时间跨度是什么,因为每次重新同步都会改变偏移量,这可能是最多20毫秒.
Mus*_*sis 56
DateTime.Now
读取的系统时钟的值仅每15 ms左右更新一次(或在某些系统上为10 ms),这就是为什么时间在这些间隔周围量化的原因.由于您的代码在多线程操作系统中运行,因此存在额外的量化效应,因此存在应用程序不"活动"并且因此不测量实际当前时间的延伸.
由于您正在寻找超精确的时间戳值(而不是仅计时任意持续时间),因此Stopwatch
该类本身无法满足您的需求.我想你必须自己做一些DateTime
/ Stopwatch
混合动力.当您的应用程序启动时,您将存储当前DateTime.UtcNow
值(即应用程序启动时的原始分辨率时间),然后还启动一个Stopwatch
对象,如下所示:
DateTime _starttime = DateTime.UtcNow;
Stopwatch _stopwatch = Stopwatch.StartNew();
Run Code Online (Sandbox Code Playgroud)
然后,只要您需要高分辨率DateTime
值,就可以这样:
DateTime highresDT = _starttime.AddTicks(_stopwatch.Elapsed.Ticks);
Run Code Online (Sandbox Code Playgroud)
你也可能想要定期重置_starttime和_stopwatch,以防止结果时间与系统时间过于不同步(虽然我不确定这实际上会发生,但无论如何都需要很长时间才能发生) .
更新:因为看起来秒表确实与系统时间不一致(每小时多半秒),我认为DateTime
根据调用之间的时间间隔重置混合类是有意义的时间:
public class HiResDateTime
{
private static DateTime _startTime;
private static Stopwatch _stopWatch = null;
private static TimeSpan _maxIdle =
TimeSpan.FromSeconds(10);
public static DateTime UtcNow
{
get
{
if ((_stopWatch == null) ||
(_startTime.Add(_maxIdle) < DateTime.UtcNow))
{
Reset();
}
return _startTime.AddTicks(_stopWatch.Elapsed.Ticks);
}
}
private static void Reset()
{
_startTime = DateTime.UtcNow;
_stopWatch = Stopwatch.StartNew();
}
}
Run Code Online (Sandbox Code Playgroud)
如果您以某个固定间隔(例如每小时或某些时间)重置混合计时器,则可能会在最后一次读取时间之前设置时间,这类似于微型夏令时问题.
Mar*_*s.D 21
要获得高分辨率的滴答计数,请使用静态Stopwatch.GetTimestamp() - 方法:
long tickCount = System.Diagnostics.Stopwatch.GetTimestamp();
DateTime highResDateTime = new DateTime(tickCount);
Run Code Online (Sandbox Code Playgroud)
只需看看.NET源代码:
public static long GetTimestamp() {
if(IsHighResolution) {
long timestamp = 0;
SafeNativeMethods.QueryPerformanceCounter(out timestamp);
return timestamp;
}
else {
return DateTime.UtcNow.Ticks;
}
}
Run Code Online (Sandbox Code Playgroud)
源代码在这里:http://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/Stopwatch.cs,69c6c3137e12dab4
Ian*_*cer 19
[接受的答案似乎不是线程安全的,并且它自己的录取可以及时倒退导致重复的时间戳,因此这个替代答案]
如果您真正关心的(根据您的评论)实际上是一个以严格升序分配并且尽可能与系统时间相对应的唯一时间戳,您可以尝试这种替代方法:
public class HiResDateTime
{
private static long lastTimeStamp = DateTime.UtcNow.Ticks;
public static long UtcNowTicks
{
get
{
long orig, newval;
do
{
orig = lastTimeStamp;
long now = DateTime.UtcNow.Ticks;
newval = Math.Max(now, orig + 1);
} while (Interlocked.CompareExchange
(ref lastTimeStamp, newval, orig) != orig);
return newval;
}
}
}
Run Code Online (Sandbox Code Playgroud)
Jam*_*zor 12
这些建议看起来都太难了!如果您使用的是Windows 8或Server 2012或更高版本,请使用GetSystemTimePreciseAsFileTime
以下命令:
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi)]
static extern void GetSystemTimePreciseAsFileTime(out long filetime);
public DateTimeOffset GetNow()
{
long fileTime;
GetSystemTimePreciseAsFileTime(out fileTime);
return DateTimeOffset.FromFileTime(fileTime);
}
Run Code Online (Sandbox Code Playgroud)
这比DateTime.Now
没有任何努力有更多,更好的准确性.
有关详细信息,请参阅MSDN:http://msdn.microsoft.com/en-us/library/windows/desktop/hh706895(v = vs.85).aspx
它确实返回操作系统已知的最准确的日期和时间.
操作系统还提供更高分辨率的时间QueryPerformanceCounter
和QueryPerformanceFrequency
(.NET Stopwatch
类).这些让你计时间隔,但不给你一天的日期和时间.你可能会争辩说,这些能够给你一个非常准确的时间和日期,但我不确定他们在很长一段时间内有多么糟糕.
归档时间: |
|
查看次数: |
50972 次 |
最近记录: |