使用Windows C++中具有毫秒精度和分辨率的时间戳记录

Dav*_*ave 8 c++ windows timestamp resolution

我知道,对于时序精度,像timeGetTime,timeBeginPeriod,QueryPerformanceCounter等功能都很棒,既提供了良好的分辨率和准确度,又只是基于启动时间,没有直接链接到时钟时间.

但是,我不想这样做时间事件.我希望能够生成一个精确的时间戳(本地时间),以便我可以在日志文件中显示它,例如31-12-2010 12:38:35.345,每个条目.(我需要毫秒精度)

标准的Windows时间函数,如GetLocalTime,虽然它们提供毫秒值,但没有毫秒级的分辨率,具体取决于运行的操作系统.我正在使用XP,所以我不能指望比大约15ms的分辨率好多了.

我需要的是一种获得两全其美的方法,而不会产生大量开销来获得所需的输出.过大的方法/计算意味着记录仪在其运行期间会开始耗费太多时间.

最好/最简单的方法是什么?

Ste*_*e-o 5

您可以尝试GetSystemAsFileTime以100纳秒为单位表示时间.您可以使用Windows来确定它填充的实际分辨率.

替代方法只是查询本地时间并用于QueryPerformanceCounter在应用程序启动时锁定偏移量与时间的比率,并将其应用于后续计数器读数.


Lio*_*gan 5

首先,一些功能:

// ==========================================================================
#define NOMINMAX
#define _AFXDLL
#include "afxwin.h"               // TRACE
#include "windows.h"              // ULARGE_INTEGER
#include "mmSystem.h"             // timeGetTime
#pragma comment(lib, "Winmm.lib") // timeGetTime

// ==========================================================================
// convert FILETIME to ULONGLONG
// (casting won't work on 64-bit platforms, due to alignment of FILETIME members)
inline void ToULL(const FILETIME& ft, ULONGLONG& uft)
{
    ULARGE_INTEGER uli;
    uli.LowPart = ft.dwLowDateTime ;
    uli.HighPart= ft.dwHighDateTime;
    uft= uli.QuadPart;
}

// --------------------------------------------------------------------------
// convert ULONGLONG to FILETIME
// (casting won't work on 64-bit platforms, due to alignment of FILETIME members)
inline void ToFILETIME(const ULONGLONG& uft, FILETIME& ft)
{
    ULARGE_INTEGER uli;
    uli.QuadPart= uft;
    ft.dwLowDateTime = uli.LowPart ;
    ft.dwHighDateTime= uli.HighPart;
}

// --------------------------------------------------------------------------
// ULONGLONG version for GetSystemTimeAsFileTime
inline void GetSystemTimeAsULL(ULONGLONG& uft)
{
    FILETIME ft;
    ::GetSystemTimeAsFileTime(&ft);
    ToULL(ft, uft);
}

// --------------------------------------------------------------------------
// convert ULONGLONG to time-components
bool ULLToSystemTime(const ULONGLONG nTime        ,  // [i]
                     WORD&           nYear        ,  // [o] 1601 - 30827
                     WORD&           nMonth       ,  // [o] 1 -    12
                     WORD&           nDay         ,  // [o] 1 -    31
                     WORD&           nHour        ,  // [o] 0 -    23
                     WORD&           nMinute      ,  // [o] 0 -    59
                     WORD&           nSecond      ,  // [o] 0 -    59
                     WORD&           nMilliseconds ) // [o] 0 -   999
{
    SYSTEMTIME sysTime;
    FILETIME   ft     ;
    ToFILETIME(nTime, ft);

    // the wDayOfWeek member of the SYSTEMTIME structure is ignored
    if (0 == ::FileTimeToSystemTime(&ft, &sysTime))
        return false;

    nYear        = sysTime.wYear        ;
    nMonth       = sysTime.wMonth       ;
    nDay         = sysTime.wDay         ;
    nHour        = sysTime.wHour        ;
    nMinute      = sysTime.wMinute      ;
    nSecond      = sysTime.wSecond      ;
    nMilliseconds= sysTime.wMilliseconds;
    return true;
}

// --------------------------------------------------------------------------
void TraceTime(const ULONGLONG nTime) // [i]
{
    WORD nYear,nMonth,nDay,nHour,nMinute,nSecond,nMilliseconds;
    ULLToSystemTime(nTime, nYear,nMonth,nDay,nHour,nMinute,nSecond,nMilliseconds);
    TRACE("Time: %02u-%02u-%04u %02u:%02u:%02u.%03u\n", nDay,nMonth,nYear,nHour,nMinute,nSecond,nMilliseconds);
}
Run Code Online (Sandbox Code Playgroud)

现在,如何使用:

ULONGLONG u0,u1;
::GetSystemTimeAsULL(u0);

// wait for tick (each 14.4mS)
do
{
    ::GetSystemTimeAsULL(u1);
}
while (u0==u1);

DWORD d1= ::timeGetTime();

// d1 and u1 are now synchronized

// ... do some work

// get current time:
ULONGLONG u2= u1+(::timeGetTime() - d1)*10000; // mSec --> HectoNanoSec

TraceTime(u2);
Run Code Online (Sandbox Code Playgroud)

请注意,您应该在2-3分钟内重新同步d1和u1一次,以保持准确性.实际上,您可以测量时钟之间的漂移,以找到最佳的重新同步间隔.