首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++初学者如何使用GetSystemTimeAsFileTime

C++初学者如何使用GetSystemTimeAsFileTime
EN

Stack Overflow用户
提问于 2015-09-09 03:27:59
回答 3查看 11.6K关注 0票数 2

我有一个程序,从系统时钟读取当前时间,并将其保存到文本文件中。我以前使用的是GetSystemTime函数,但时间并不完全一致,例如:一次是32567.789次,下一次是32567.780次,时间是反向的。

我正在使用这个程序来节省高达10次每秒的时间。我读到GetSystemTimeAsFileTime函数更精确。我的问题是,如何将当前代码转换为使用GetSystemTimeAsFileTime函数?我试图使用FileTimeToSystemTime函数,但这也有同样的问题。

代码语言:javascript
运行
复制
SYSTEMTIME st;
GetSystemTime(&st);

WORD sec = (st.wHour*3600) + (st.wMinute*60) + st.wSecond; //convert to seconds in a day
lStr.Format( _T("%d   %d.%d\n"),GetFrames() ,sec, st.wMilliseconds);

std::wfstream myfile;  
myfile.open("time.txt", std::ios::out | std::ios::in | std::ios::app );
if (myfile.is_open())
    {
     myfile.write((LPCTSTR)lStr, lStr.GetLength());
     myfile.close();
    }
else {lStr.Format( _T("open file failed: %d"), WSAGetLastError());
}           

编辑以添加更多信息,代码从摄像机中捕获图像,每秒钟运行10次,并将图像保存到文本文件中。当我从第二个文件中减去文本文件的第一个条目时,例如:条目2-1、3-2、4-3等等,我得到了这个图,其中x轴是条目的数目,y轴是减去的值。

他们都应该在0.12分左右,这是他们中的大多数。然而,你可以看到,其中有很多是不同的,有些甚至是负面的。这不是由于相机,因为相机有它自己的内部时钟,而且没有变化。它与捕获系统时间有关。我想要的是最准确的方法来提取系统的时间,以最高的分辨率和尽可能少的噪音。

编辑2我已经采纳了您的建议,并再次运行程序。其结果是:

正如你所看到的,它比以前好多了,但还是不对。我觉得奇怪的是,它似乎越来越多地这样做了。我还绘制了时间图,这是结果,其中x是条目,y是时间:

有没有人知道是什么导致每隔30帧就出去一次?

EN

回答 3

Stack Overflow用户

发布于 2015-09-09 03:47:26

首先,您需要按以下方式获得FILETIME

代码语言:javascript
运行
复制
FILETIME fileTime;
GetSystemTimeAsFileTime(&fileTime);
// Or for higher precision, use
// GetSystemTimePreciseAsFileTime(&fileTime);

根据FILETIME's 文档的说法

不建议从FILETIME结构中添加和减去值以获得相对时间。相反,您应该将文件时间的低阶和高阶部分复制到ULARGE_INTEGER结构中,对QuadPart成员执行64位算法,并将LowPart和HighPart成员复制到FILETIME结构中。

所以,接下来你应该做的是

代码语言:javascript
运行
复制
ULARGE_INTEGER theTime;
theTime.LowPart = fileTime.dwLowDateTime;
theTime.HighPart = fileTime.dwHighDateTime;

__int64 fileTime64Bit = theTime.QuadPart;

就是这样。fileTime64Bit变量现在包含您正在寻找的时间。

如果您想要获得一个SYSTEMTIME对象,只需执行以下操作:

代码语言:javascript
运行
复制
SYSTEMTIME systemTime;
FileTimeToSystemTime(&fileTime, &systemTime);
票数 6
EN

Stack Overflow用户

发布于 2015-09-10 08:48:07

让系统时间以相当高的准确性离开Windows也是我玩得很开心的东西.我发现运行在Chrome上的Javascript代码似乎产生了比使用C++代码更一致的计时器结果,所以我查看了Chrome源代码。一个有趣的起点是铬源中的win.cc顶部的评论。给出的链接到Mozilla bug和Dobb博士的文章也非常有趣。

基于Mozilla和Chrome源代码以及上面的链接,我自己生成的代码是这里。正如你所看到的,这是很多代码!

基本思想是,获得绝对电流时间是相当昂贵的。Windows确实提供了一个高分辨率的计时器,访问起来很便宜,但这只会给您相对的时间,而不是绝对的时间。我的代码将问题分成两部分:

1)准确获取系统时间。这是在CalibrateNow()中。基本技术是调用timeBeginPeriod(1)以获得精确的时间,然后调用GetSystemTimeAsFileTime(),直到结果发生变化,这意味着timeBeginPeriod()调用产生了效果。这给了我们一个准确的系统时间,但这是一个非常昂贵的操作( timeBeginPeriod()调用可能会影响其他进程),因此我们不希望每次需要时间时都这样做。代码还调用QueryPerformanceCounter()来获取当前高分辨率计时器值。

代码语言:javascript
运行
复制
bool NeedCalibration = true;
LONGLONG CalibrationFreq = 0;
LONGLONG CalibrationCountBase = 0;
ULONGLONG CalibrationTimeBase = 0;

void CalibrateNow(void)
{
  // If the timer frequency is not known, try to get it
  if (CalibrationFreq == 0)
  {
    LARGE_INTEGER freq;
    if (::QueryPerformanceFrequency(&freq) == 0)
      CalibrationFreq = -1;
    else
      CalibrationFreq = freq.QuadPart;
  }

  if (CalibrationFreq > 0)
  {
    // Get the current system time, accurate to ~1ms
    FILETIME ft1, ft2;
    ::timeBeginPeriod(1);
    ::GetSystemTimeAsFileTime(&ft1);
    do
    {
      // Loop until the value changes, so that the timeBeginPeriod() call has had an effect
      ::GetSystemTimeAsFileTime(&ft2);
    }
    while (FileTimeToValue(ft1) == FileTimeToValue(ft2));
    ::timeEndPeriod(1);

    // Get the current timer value
    LARGE_INTEGER counter;
    ::QueryPerformanceCounter(&counter);

    // Save calibration values
    CalibrationCountBase = counter.QuadPart;
    CalibrationTimeBase = FileTimeToValue(ft2);
    NeedCalibration = false;
  }
}

2)当我们想要当前时间时,通过调用QueryPerformanceCounter()获得高分辨率计时器,并使用自上次CalibrateNow()调用以来对该计时器的更改来计算出一个准确的“立即”。这已经在我的代码中了。这也会定期调用CalibrateNow(),以确保系统时间不会倒退或漂移。

代码语言:javascript
运行
复制
FILETIME GetNow(void)
{
  for (int i = 0; i < 4; i++)
  {
    // Calibrate if needed, and give up if this fails
    if (NeedCalibration)
      CalibrateNow();
    if (NeedCalibration)
      break;

    // Get the current timer value and use it to compute now
    FILETIME ft;
    ::GetSystemTimeAsFileTime(&ft);
    LARGE_INTEGER counter;
    ::QueryPerformanceCounter(&counter);
    LONGLONG elapsed = ((counter.QuadPart - CalibrationCountBase) * 10000000) / CalibrationFreq;
    ULONGLONG now = CalibrationTimeBase + elapsed;

    // Don't let time go back
    static ULONGLONG lastNow = 0;
    now = max(now,lastNow);
    lastNow = now;

    // Check for clock skew
    if (LONGABS(FileTimeToValue(ft) - now) > 2 * GetTimeIncrement())
    {
      NeedCalibration = true;
      lastNow = 0;
    }

    if (!NeedCalibration)
      return ValueToFileTime(now);
  }

  // Calibration has failed to stabilize, so just use the system time
  FILETIME ft;
  ::GetSystemTimeAsFileTime(&ft);
  return ft;
}

虽然有点多毛,但效果比我希望的要好。这似乎也很好地工作在Windows上,就像我测试过的那样(也就是Windows )。

票数 4
EN

Stack Overflow用户

发布于 2015-09-09 04:32:43

我相信您正在寻找的是GetSystemTimePreciseAsFileTime()函数,甚至是QueryPerformanceCounter() --它是被保护以生成单调值的东西的缩写。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32470442

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档