Windows下与gettimeofday()等效的函数

37

有没有人知道Windows环境下与gettimeofday()函数等效的函数?我正在比较在Linux和Windows中执行代码的时间。我正在使用MS Visual Studio 2010,但它一直提示"gettimeofday"未定义。


2
可能是重复的问题:在Windows上用什么替换gettimeofday()? - James M
6个回答

86

这里是一个免费的实现:

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <stdint.h> // portable: uint64_t   MSVC: __int64 

// MSVC defines this in winsock2.h!?
typedef struct timeval {
    long tv_sec;
    long tv_usec;
} timeval;

int gettimeofday(struct timeval * tp, struct timezone * tzp)
{
    // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
    // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
    // until 00:00:00 January 1, 1970 
    static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);

    SYSTEMTIME  system_time;
    FILETIME    file_time;
    uint64_t    time;

    GetSystemTime( &system_time );
    SystemTimeToFileTime( &system_time, &file_time );
    time =  ((uint64_t)file_time.dwLowDateTime )      ;
    time += ((uint64_t)file_time.dwHighDateTime) << 32;

    tp->tv_sec  = (long) ((time - EPOCH) / 10000000L);
    tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
    return 0;
}

非常好。我有一段代码,其中包含了这个实现。完全相同的代码,但我需要让这段代码在Linux上运行,而我不知道该怎么做。我应该如何使用C++或C来实现这段代码,在Linux上编译并使用这个相同的实现呢?谢谢。 - S4nD3r
2
@S4nD3r #ifdef _WIN32 ...上面有包含的代码行... #else #include <sys/time.h> #endif ... 在我的Buddhabrot项目中可以看到我的用法:https://raw.githubusercontent.com/Michaelangel007/buddhabrot/master/buddhabrot.cpp - Michaelangel007
我知道这已经过时了,但为什么要传递tzp,因为它没有被引用到? - SPlatten
为了与 sys/time.h 实现二进制兼容: int gettimeofday(struct timeval *tv, struct timezone *tz); int settimeofday(const struct timeval *tv, const struct timezone *tz); - Michaelangel007
@SPlatten tz 永远不应该是除了 null 以外的任何东西...它只在 Linux 内核中使用,而且已被标记为弃用。 - Swift - Friday Pie

18

GetLocalTime()函数获取系统时区的本地时间,GetSystemTime()函数获取UTC时间。这两个函数返回一个SYSTEMTIME结构体,其中解析出年、月等信息。如果需要秒数自历元以来的时间戳,可以使用SystemTimeToFileTime()或者GetSystemTimeAsFileTime()函数。其中FILETIME是一个64位值,表示自1601年1月1日UTC以来的100纳秒间隔数。

获取时间间隔,可以使用GetTickCount()函数,它返回自启动以来的毫秒数。

为了获得更高的分辨率(受硬件限制),可以使用QueryPerformanceCounter()函数。


10
这是使用chrono的c++11版本。
感谢Howard Hinnant提供的建议。
#if defined(_WIN32)
#include <chrono>

int gettimeofday(struct timeval* tp, struct timezone* tzp) {
  namespace sc = std::chrono;
  sc::system_clock::duration d = sc::system_clock::now().time_since_epoch();
  sc::seconds s = sc::duration_cast<sc::seconds>(d);
  tp->tv_sec = s.count();
  tp->tv_usec = sc::duration_cast<sc::microseconds>(d - s).count();

  return 0;
}

#endif // _WIN32

3
请勿仅发布代码,请解释它的功能以及如何解决问题。 - Max Vollmer
1
请参考 https://dev59.com/KXPYa4cB1Zd3GeqPpPIo#32763779,了解将 chrono 类型转换为 C 时间 API 类型的更好方法。 - Howard Hinnant

4

4

现在,如果编译为Windows 8或更高版本,则会使用GetSystemTimePreciseAsFileTime(),否则会使用GetSystemTimeAsFileTime(),以获取Windows上gettimeofday()的当前时间。

#include <Windows.h>
struct timezone {
    int tz_minuteswest;
    int tz_dsttime;
};

int gettimeofday(struct timeval *tv, struct timezone *tz)
{
    if (tv) {
        FILETIME               filetime; /* 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 00:00 UTC */
        ULARGE_INTEGER         x;
        ULONGLONG              usec;
        static const ULONGLONG epoch_offset_us = 11644473600000000ULL; /* microseconds betweeen Jan 1,1601 and Jan 1,1970 */

#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
        GetSystemTimePreciseAsFileTime(&filetime);
#else
        GetSystemTimeAsFileTime(&filetime);
#endif
        x.LowPart =  filetime.dwLowDateTime;
        x.HighPart = filetime.dwHighDateTime;
        usec = x.QuadPart / 10  -  epoch_offset_us;
        tv->tv_sec  = (time_t)(usec / 1000000ULL);
        tv->tv_usec = (long)(usec % 1000000ULL);
    }
    if (tz) {
        TIME_ZONE_INFORMATION timezone;
        GetTimeZoneInformation(&timezone);
        tz->tz_minuteswest = timezone.Bias;
        tz->tz_dsttime = 0;
    }
    return 0;
}

0
自 Visual Studio 2015 起,timespec_get 已经可用:

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static uint64_t
time_ns(void)
{
    struct timespec ts;

    if (timespec_get(&ts, TIME_UTC) != TIME_UTC)
    {
        fputs("timespec_get failed!", stderr);
        return 0;
    }
    return 1000000000 * ts.tv_sec + ts.tv_nsec;
}

int main(void)
{
    printf("%" PRIu64 "\n", time_ns());
    return EXIT_SUCCESS;
}

使用 cl t.c 进行编译并运行:

C:\> perl -E "system 't' for 1 .. 10"
1626610781959535900
1626610781973206600
1626610781986049300
1626610781999977000
1626610782014814800
1626610782028317500
1626610782040880700
1626610782054217800
1626610782068346700
1626610782081375500

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接