天天看點

C++ Tips: 擷取更精确的系統時間(Windows 系統)精确到秒的 std::time精确到毫秒的 GetSystemTime / GetLocalTime精确到 100 納秒的 GetSystemTimeAsFileTime

精确到秒的 std::time

為了獲得系統目前時間,目前 C++ 标準庫裡面給出的方法是 std::time,它傳回的結構體是 std::time_t。這個方法很友善很通用,但它有一些局限:

  1. 它是精确到秒的。如果您需要更高精度的時間,比如說您需要精确到毫秒,那麼它不合适。
  2. 它表示從 Epoch (1970年1月1日00:00:00)到現在所經過的秒數。最初 std::time_t 的定義是 32 位的,是以它的時間最多能表示到 2038年1月19日 03:14:07 (GMT時間),再過 1 秒,std::time 的傳回就會變成 1901年12月13日 20:45:52 (GMT時間)。這就是著名的 Year 2038 problem。話說 2038 年好像看起來也不太遙遠了。
  3. 在某些系統上(比如說我現在正在使用的Windows 7 64位),std::time_t 的定義變成了 64 位。這樣就暫時給這個函數從死刑改判成死緩了。std::time_t 的定義從 32 位改為 64 位隻是延長了它所表示的時間範圍,但并沒有改變它的精度,依然是精确到秒。

下面給出示範程式:

// GetSystemTime.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <ctime>
#include <iostream>


#define BUF_SIZE 26

int _tmain(void)
{
    TCHAR buf[BUF_SIZE] = {  };
    errno_t err;
    std::time_t cur_time;

    /* Obtain current time as seconds elapsed since the Epoch. */
    cur_time = std::time(nullptr);

    if (cur_time == ((time_t)-))
    {
        fprintf_s(stderr, "Failure to compute the current time.\n");
        goto EXIT;
    }

    /* Convert to local time format. */
    err = _tctime_s(buf, BUF_SIZE, &cur_time);
    if (err != )
    {
        _tprintf_s(_T("Invalid Arguments for _wctime_s. Error Code: %d\n"), err);
        goto EXIT;
    }

    _tprintf_s(_T("The local time is %s\n"), buf);

EXIT:
    return ;
}

           

執行結果:

C++ Tips: 擷取更精确的系統時間(Windows 系統)精确到秒的 std::time精确到毫秒的 GetSystemTime / GetLocalTime精确到 100 納秒的 GetSystemTimeAsFileTime

精确到毫秒的 GetSystemTime / GetLocalTime

Windows SDK 中有兩個精确到毫秒的擷取目前時間的函數:

  • GetSystemTime:擷取 UTC 時間。
  • GetLocalTime:擷取當地時間。

這兩個函數的傳回都是:SYSTEMTIME

這個結構體占用了 16 個位元組,它的定義如下:

typedef struct _SYSTEMTIME {
  WORD wYear;
  WORD wMonth;
  WORD wDayOfWeek;
  WORD wDay;
  WORD wHour;
  WORD wMinute;
  WORD wSecond;
  WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;
           

其中 wYear 表示的範圍是:從 1601 到 30827。範圍很廣了,應該能用到天荒地老了。:-)

示範程式:

// GetSystemTime.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>

int _tmain(void)
{
    SYSTEMTIME utc_time = {  };
    SYSTEMTIME local_time = {  };

    GetSystemTime(&utc_time);
    GetLocalTime(&local_time);

    _tprintf(_T("The UTC time is \t: %02d:%02d:%02d.%03d\n"), utc_time.wHour, utc_time.wMinute, utc_time.wSecond, utc_time.wMilliseconds);
    _tprintf(_T("The local time is\t: %02d:%02d:%02d.%03d\n"), local_time.wHour, local_time.wMinute, local_time.wSecond, local_time.wMilliseconds);

    return ;
}
           

運作結果:

C++ Tips: 擷取更精确的系統時間(Windows 系統)精确到秒的 std::time精确到毫秒的 GetSystemTime / GetLocalTime精确到 100 納秒的 GetSystemTimeAsFileTime

精确到 100 納秒的 GetSystemTimeAsFileTime

究竟能不能達到 100 納秒的精确度呢?在 Windows SDK 中有一個結構體:FILETIME,它可以記錄精度達到 100ns 的時間。用哪個函數得到這個值呢?可以用 GetSystemTimeAsFileTime。

但是,不要高興得太早,雖然 FILETIME 能夠達到如此高的精度,但是這個函數我連試都懶得試。為什麼呢?因為 Windows 系統并不是一個實時作業系統(Windows Embedded Compact 2013 是一個實時系統),其時鐘精度一般認為是 15 ~ 16 毫秒。

Windows Sysinternals 給我們提供了一個檢視你使用的 Windows 系統的時鐘分辨率的小工具:ClockRes v2.0。把它下載下傳下來在控制台中執行,結果如下:

C++ Tips: 擷取更精确的系統時間(Windows 系統)精确到秒的 std::time精确到毫秒的 GetSystemTime / GetLocalTime精确到 100 納秒的 GetSystemTimeAsFileTime

看到了吧。死心了吧。

是以說,用 GetSystemTime / GetLocalTime 就已經很好了。

如果要獲得真正毫秒級甚至更高精度的目前系統時間,必須跟 CPU 打交道,别無它法。