Как я могу получить системное время Windows с разрешением в миллисекундах? - PullRequest
20 голосов
/ 16 сентября 2010

Как узнать системное время Windows с разрешением в миллисекундах?

Если вышеописанное невозможно, то как узнать время запуска операционной системы? Я хотел бы использовать это значение вместе с timeGetTime () для вычисления системного времени с разрешением в миллисекундах.

Заранее спасибо.

Ответы [ 10 ]

21 голосов
/ 16 сентября 2010

Попробуйте эту статью из журнала MSDN.Это на самом деле довольно сложно.

Реализация постоянно обновляемого поставщика времени с высоким разрешением для Windows

11 голосов
/ 20 сентября 2010

Это пояснение вышеприведенных комментариев для объяснения некоторых причин.

Во-первых, вызовы GetSystemTime * являются единственными Win32 API, обеспечивающими системное время.Это время имеет довольно грубую детализацию, так как большинству приложений не нужны служебные данные, необходимые для поддержания более высокого разрешения.Время (вероятно) хранится внутри как 64-битный отсчет миллисекунд.Вызов timeGetTime получает младшие 32 бита.Вызов GetSystemTime и т. Д. Требует, чтобы Windows возвращала это время в миллисекундах, после преобразования в дни и т. Д., Включая время запуска системы.

В машине есть два источника времени: часы процессора и встроенные часы (например, часы реального времени (RTC), программируемые интервальные таймеры (PIT) и высокоточный таймер событий (HPET)).Первый имеет разрешение около 0,5 нс (2 ГГц), а второй обычно программируется с периодом до 1 мс (хотя более новые чипы (HPET) имеют более высокое разрешение).Windows использует эти периодические тики для выполнения определенных операций, включая обновление системного времени.

Приложения могут изменять этот период с помощью timerBeginPeriod ;однако это влияет на всю систему.ОС будет проверять / обновлять регулярные события с запрошенной периодичностью.При низких нагрузках / частотах процессора существуют периоды простоя для экономии энергии.На высоких частотах нет времени переводить процессор в состояние пониженного энергопотребления.См. Разрешение таймера для получения дополнительной информации.Наконец, каждый тик имеет некоторые издержки, и увеличение частоты потребляет больше тактов ЦП.

При более высоком разрешении системное время не поддерживается с такой точностью, не более чем у Биг-Бена есть секундная стрелка.Использование QueryPerformanceCounter (QPC) или тиков процессора (rdtsc) может обеспечить разрешение между тиками системного времени.Такой подход использовался в статье в журнале MSDN, на которую ссылался Кевин.Хотя эти подходы могут иметь дрейф (например, из-за масштабирования частоты) и т. Д., И поэтому их необходимо синхронизировать с системным временем.

7 голосов
/ 16 сентября 2010

GetTickCount не сделает это за вас.

Загляните в QueryPerformanceFrequency / QueryPerformanceCounter.Единственное, что здесь есть, так это масштабирование процессора, так что сделайте свое исследование.

6 голосов
/ 22 августа 2017

В Windows основой всего времени является функция с именем GetSystemTimeAsFiletime.

  • Возвращает структуру, способную удерживать время с разрешением 100 нс.
  • Хранится в UTC

Структура FILETIME записывает количество интервалов в 100 нс с 1 января 1600 года; это означает, что его разрешение ограничено 100 нс.

Это формирует нашу первую функцию:

enter image description here

64-битное число тиков в 100 нс с 1 января 1600 года несколько громоздко. Windows предоставляет удобную вспомогательную функцию FileTimeToSystemTime, которая может декодировать это 64-разрядное целое число в полезные части:

record SYSTEMTIME {
   wYear: Word;
   wMonth: Word;
   wDayOfWeek: Word;
   wDay: Word;
   wHour: Word;
   wMinute: Word;
   wSecond: Word;
   wMilliseconds: Word;
}

Обратите внимание, что SYSTEMTIME имеет встроенное ограничение разрешения 1ms

Теперь у нас есть путь от FILETIME до SYSTEMTIME:

enter image description here

Мы могли бы написать функцию для получения текущего системного времени в виде SYSTEIMTIME структуры:

SYSTEMTIME GetSystemTime()
{
    //Get the current system time utc in it's native 100ns FILETIME structure
    FILETIME ftNow;
    GetSytemTimeAsFileTime(ref ft);

    //Decode the 100ns intervals into a 1ms resolution SYSTEMTIME for us
    SYSTEMTIME stNow;
    FileTimeToSystemTime(ref stNow);

    return stNow;
}

За исключением того, что Windows уже написала для вас такую ​​функцию: GetSystemTime

enter image description here

Местный, а не UTC

А теперь, если вы не хотите, чтобы текущее время было в UTC. Что делать, если вы хотите это по местному времени? Windows предоставляет функцию для преобразования FILETIME в UTC в ваше местное время: FileTimeToLocalFileTime

enter image description here

Вы могли бы написать функцию, которая возвращает вам FILETIME в локальном времени уже:

FILETIME GetLocalTimeAsFileTime()
{
   FILETIME ftNow;
   GetSystemTimeAsFileTime(ref ftNow);

   //convert to local
   FILETIME ftNowLocal
   FileTimeToLocalFileTime(ftNow, ref ftNowLocal);

   return ftNowLocal;
}

enter image description here

Допустим, вы хотите декодировать локальный FILETIME в SYSTEMTIME. Это не проблема, вы можете использовать FileTimeToSystemTime снова:

enter image description here

К счастью, Windows уже предоставляет вам функцию, которая возвращает вам значение:

enter image description here

Precise

Есть еще одно соображение. До Windows 8 часы имели разрешение около 15 мс. В Windows 8 они улучшили время до 100 нс (что соответствует разрешению FILETIME).

  • GetSystemTimeAsFileTime (устаревшее, разрешение 15 мс)
  • GetSystemTimeAsPreciseFileTime (Windows 8, разрешение 100 нс)

Это означает, что мы всегда должны отдавать предпочтение новому значению:

enter image description here

Вы попросили время

Вы спросили время; но у вас есть выбор.

Часовой пояс:

  • UTC (системная система)
  • Местный часовой пояс

Формат:

  • FILETIME (системный, разрешение 100 нс)
  • SYTEMTIME (расшифровано, разрешение 1 мс)

Резюме

  • UTC: GetSytemTimeAsPreciseFileTime (или GetSystemTimeAsFileTime)
  • Местный: (сверните свой)
* Разрешение 1159 * 1 мс: SYSTEMTIME
  • UTC: GetSystemTime
  • Местный: GetLocalTime
4 голосов
/ 29 апреля 2015

Начиная с Windows 8 Microsoft представила новую команду API GetSystemTimePreciseAsFileTime:

https://msdn.microsoft.com/en-us/library/windows/desktop/hh706895%28v=vs.85%29.aspx

К сожалению, вы не сможете использовать это, если создаете программное обеспечение, которое также должно работать в старых операционных системах..

Мое текущее решение заключается в следующем, но помните: установленное время не является точным, оно только близко к реальному времени.Результат всегда должен быть меньше или равен реальному времени, но с фиксированной ошибкой (если только компьютер не перешел в режим ожидания).Результат имеет разрешение в миллисекундах.Для моей цели это достаточно точно.

void GetHighResolutionSystemTime(SYSTEMTIME* pst)
{
    static LARGE_INTEGER    uFrequency = { 0 };
    static LARGE_INTEGER    uInitialCount;
    static LARGE_INTEGER    uInitialTime;
    static bool             bNoHighResolution = false;

    if(!bNoHighResolution && uFrequency.QuadPart == 0)
    {
        // Initialize performance counter to system time mapping
        bNoHighResolution = !QueryPerformanceFrequency(&uFrequency);
        if(!bNoHighResolution)
        {
            FILETIME ftOld, ftInitial;

            GetSystemTimeAsFileTime(&ftOld);
            do
            {
                GetSystemTimeAsFileTime(&ftInitial);
                QueryPerformanceCounter(&uInitialCount);
            } while(ftOld.dwHighDateTime == ftInitial.dwHighDateTime && ftOld.dwLowDateTime == ftInitial.dwLowDateTime);
            uInitialTime.LowPart  = ftInitial.dwLowDateTime;
            uInitialTime.HighPart = ftInitial.dwHighDateTime;
        }
    }

    if(bNoHighResolution)
    {
        GetSystemTime(pst);
    }
    else
    {
        LARGE_INTEGER   uNow, uSystemTime;

        {
            FILETIME    ftTemp;
            GetSystemTimeAsFileTime(&ftTemp);
            uSystemTime.LowPart  = ftTemp.dwLowDateTime;
            uSystemTime.HighPart = ftTemp.dwHighDateTime;
        }
        QueryPerformanceCounter(&uNow);

        LARGE_INTEGER   uCurrentTime;
        uCurrentTime.QuadPart = uInitialTime.QuadPart + (uNow.QuadPart - uInitialCount.QuadPart) * 10000000 / uFrequency.QuadPart;

        if(uCurrentTime.QuadPart < uSystemTime.QuadPart || abs(uSystemTime.QuadPart - uCurrentTime.QuadPart) > 1000000)
        {
            // The performance counter has been frozen (e. g. after standby on laptops)
            // -> Use current system time and determine the high performance time the next time we need it
            uFrequency.QuadPart = 0;
            uCurrentTime = uSystemTime;
        }

        FILETIME ftCurrent;
        ftCurrent.dwLowDateTime  = uCurrentTime.LowPart;
        ftCurrent.dwHighDateTime = uCurrentTime.HighPart;
        FileTimeToSystemTime(&ftCurrent, pst);
    }
}
1 голос
/ 16 сентября 2010

GetSystemTimeAsFileTime обеспечивает наилучшую точность любой функции Win32 за абсолютное время.QPF / QPC, как предположил Джоэл Кларк, даст лучшее относительное время.

0 голосов
/ 17 ноября 2018

Поскольку мы все пришли сюда за быстрыми отрывками вместо скучных объяснений, я напишу один:

FILETIME t;
GetSystemTimeAsFileTime(&t); // unusable as is

ULARGE_INTEGER i;
i.LowPart = t.dwLowDateTime;
i.HighPart = t.dwHighDateTime;

int64_t ticks_since_1601 = i.QuadPart; // now usable
int64_t us_since_1601   = (i.QuadPart * 1e-1);
int64_t ms_since_1601   = (i.QuadPart * 1e-4);
int64_t sec_since_1601  = (i.QuadPart * 1e-7);

// unix epoch
int64_t unix_us  = (i.QuadPart * 1e-1) - 11644473600LL * 1000000;
int64_t unix_ms  = (i.QuadPart * 1e-4) - 11644473600LL * 1000;
double  unix_sec = (i.QuadPart * 1e-7) - 11644473600LL;

// i.QuadPart is # of 100ns ticks since 1601-01-01T00:00:00Z
// difference to Unix Epoch is 11644473600 seconds (attention to units!)

Понятия не имею, как пошли дрейфующие ответы, основанные на счетчиках производительности, не делайте ошибок, парни.

0 голосов
/ 23 мая 2014

Я написал некоторую информацию о том, как реализовать это быстро и легко способом, подходящим для большинства целей, в своем ответе на вопрос «Метки времени микросекунды в Windows» .

0 голосов
/ 22 марта 2014

Ну, эта версия очень старая, но есть еще одна полезная функция в библиотеке Windows C _ftime, которая возвращает структуру с местным временем как time_t, миллисекунды, часовой пояс и летнее флаг времени.

0 голосов
/ 05 декабря 2012

QueryPerformanceCounter () создан для детального разрешения таймера.

Это таймер с самым высоким разрешением, который система может предложить, который вы можете использовать в своем коде приложения для выявления узких мест производительности

Вот простая реализация для разработчиков на C #:

    [DllImport("kernel32.dll")]
    extern static short QueryPerformanceCounter(ref long x);
    [DllImport("kernel32.dll")]
    extern static short QueryPerformanceFrequency(ref long x);
    private long m_endTime;
    private long m_startTime;
    private long m_frequency;

    public Form1()
    {
        InitializeComponent();
    }
    public void Begin()
    {
        QueryPerformanceCounter(ref m_startTime);
    }
    public void End()
    {
        QueryPerformanceCounter(ref m_endTime);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        QueryPerformanceFrequency(ref m_frequency);
        Begin();
        for (long i = 0; i < 1000; i++) ;
        End();
        MessageBox.Show((m_endTime - m_startTime).ToString());
    }

Если вы являетесь разработчиком C / C ++, посмотрите здесь: http://support.microsoft.com/kb/815668

...