C编程语言中的时间戳

27

如何在C语言中对两个时间戳t1和t2进行计算并返回以毫秒为单位的时间差?


6
仅使用标准的 C 无法做到那样的事情。对于 Linux、Windows、手机、收银机、微波炉等设备,可行的解决方案都将不同。 - pmg
@Christoph:time()和clock()都可以返回-1(转换为适当的类型)来表示该实现中函数不可用...而且time()在可用时,其分辨率为1秒或更差。我查阅了标准,但没有找到任何关于clock()函数的硬限制。 - pmg
1
在Linux手册页面中:请注意时间可能会绕回。在一个32位系统上,其中CLOCKS_PER_SEC等于1000000,此函数将每约72分钟返回相同的值。要获取CPU时间,getrusage()更好,尽管clock是ANSI C的一部分,但getrusage/gettimeofday()不是。 - user172818
11个回答

32

这将给你秒和微秒的时间

#include <sys/time.h>
struct timeval tv;
gettimeofday(&tv,NULL);
tv.tv_sec // seconds
tv.tv_usec // microseconds

9

标准C99:

#include <time.h>

time_t t0 = time(0);
// ...
time_t t1 = time(0);
double datetime_diff_ms = difftime(t1, t0) * 1000.;

clock_t c0 = clock();
// ...
clock_t c1 = clock();
double runtime_diff_ms = (c1 - c0) * 1000. / CLOCKS_PER_SEC;

类型的精度是实现定义的,即日期时间差可能只返回完整的秒数。


日期时间差异最好以完整秒数返回。如果我正确理解标准,当time()不返回(time_t)-1时,并不能保证它每秒返回新值:例如,它可能具有5秒或1分钟的分辨率。 - pmg
2
@pmg:精度是实现定义的,例如在我的系统上,time()具有1s分辨率; clock()的精度通常尽可能高,但它测量的是运行时间而不是日期时间。 - Christoph

6
/*
 Returns the current time.
*/

char *time_stamp(){

char *timestamp = (char *)malloc(sizeof(char) * 16);
time_t ltime;
ltime=time(NULL);
struct tm *tm;
tm=localtime(&ltime);

sprintf(timestamp,"%04d%02d%02d%02d%02d%02d", tm->tm_year+1900, tm->tm_mon, 
    tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
return timestamp;
}


int main(){

printf(" Timestamp: %s\n",time_stamp());
return 0;

}

输出:时间戳:20110912130940 // 2011年9月12日13:09:40


你可以使用asctime(tm)返回一个字符串,而不是格式化数据。 - Ramy Al Zuhouri

6

如果您想查找经过的时间,只要在开始和结束之间不重新启动计算机,此方法就可以使用。

在Windows中,使用GetTickCount()。以下是操作步骤:

DWORD dwStart = GetTickCount();
...
... process you want to measure elapsed time for
...
DWORD dwElapsed = GetTickCount() - dwStart;

dwElapsed现在是已经过去的毫秒数。

在Linux中,使用clock()CLOCKS_PER_SEC可以实现类似的功能。

如果你需要跨重启或跨计算机的时间戳(这需要相当好的同步),那么请使用其他方法(如gettimeofday())。

此外,在Windows中,您可以获得比标准时间分辨率更高的精度。通常,如果您在一个紧密的循环中调用GetTickCount(),每次它改变时都会看到它跳动10-50。这是由Windows线程调度器使用的时间量决定的。这基本上是它在切换到其他内容之前给予每个线程运行的时间量。如果您执行以下操作:

timeBeginPeriod(1);

在您的程序或进程开始时使用:

timeEndPeriod(1);

在最后,时间量子将变为1毫秒,这样您在调用GetTickCount()时将获得更好的时间分辨率。但是,这确实会对整个计算机运行进程的方式产生微妙的变化,请注意这一点。但是,Windows Media Player和许多其他应用程序通常都会这样做,所以我不太担心。
我相信在Linux中可能有一些方法可以做到同样的事情(可能具有更好的控制,或者使用亚毫秒时间量子),但我还没有在Linux中需要这样做。

3

使用@Arkaitz Jimenez的代码获取两个timeval:

#include <sys/time.h>
//...
struct timeval tv1, tv2, diff;

// get the first time:
gettimeofday(&tv1, NULL);

// do whatever it is you want to time
// ...

// get the second time:
gettimeofday(&tv2, NULL);

// get the difference:

int result = timeval_subtract(&diff, &tv1, &tv2);

// the difference is storid in diff now.

可以在这个网站找到timeval_subtract的示例代码:

 /* Subtract the `struct timeval' values X and Y,
    storing the result in RESULT.
    Return 1 if the difference is negative, otherwise 0.  */

 int
 timeval_subtract (result, x, y)
      struct timeval *result, *x, *y;
 {
   /* Perform the carry for the later subtraction by updating y. */
   if (x->tv_usec < y->tv_usec) {
     int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
     y->tv_usec -= 1000000 * nsec;
     y->tv_sec += nsec;
   }
   if (x->tv_usec - y->tv_usec > 1000000) {
     int nsec = (x->tv_usec - y->tv_usec) / 1000000;
     y->tv_usec += 1000000 * nsec;
     y->tv_sec -= nsec;
   }

   /* Compute the time remaining to wait.
      tv_usec is certainly positive. */
   result->tv_sec = x->tv_sec - y->tv_sec;
   result->tv_usec = x->tv_usec - y->tv_usec;

   /* Return 1 if result is negative. */
   return x->tv_sec < y->tv_sec;
 }

timeval_subtract中的代码很糟糕,因为它修改了输入值y。如果输入是两个struct timeval值而不是指针,那么情况就不会那么糟糕。但是,在计算“x-y”时,你通常不希望改变存储在“y”中的值。 - Jonathan Leffler
@Jonathan,没错。不过将其更改为传递副本的实现就可以解决这个问题了。 - Glen
我同意。我想修复它,但是我现在无法双重检查我的更改是否能够编译通过,所以我觉得最好将其保持原样。 - Bill

2
这个方案怎么样?在我的搜索中没有看到类似的东西。我试图避免除法并使解决方案更简单。
   struct timeval cur_time1, cur_time2, tdiff;

   gettimeofday(&cur_time1,NULL);
   sleep(1);
   gettimeofday(&cur_time2,NULL);

   tdiff.tv_sec = cur_time2.tv_sec - cur_time1.tv_sec;
   tdiff.tv_usec = cur_time2.tv_usec + (1000000 - cur_time1.tv_usec);

   while(tdiff.tv_usec > 1000000)
   {
      tdiff.tv_sec++;
      tdiff.tv_usec -= 1000000;
      printf("updated tdiff tv_sec:%ld tv_usec:%ld\n",tdiff.tv_sec, tdiff.tv_usec);
   }

   printf("end tdiff tv_sec:%ld tv_usec:%ld\n",tdiff.tv_sec, tdiff.tv_usec);

1

还需要注意clock()和usleep()之间的交互作用。 usleep()会暂停程序运行,而clock()只测量程序正在运行的时间。

如果可能的话,最好使用gettimeofday(),如此处所述。


0
#include <sys/time.h>

time_t tm = time(NULL);
char stime[4096];
ctime_r(&tm, stime);
stime[strlen(stime) - 1] = '\0';
printf("%s",stime);

0

这个程序清楚地展示了如何做到这一点。它需要1秒的时间暂停,然后再花费时间2,两个时间之间的差应该是1000毫秒。所以你的答案是正确的。

#include <stdio.h>
#include <time.h>
#include <unistd.h>

// Name: miliseconds.c
// gcc /tmp/miliseconds.c -o miliseconds

struct timespec ts1, ts2; // time1 and time2

int main (void) {

    // get time1
    clock_gettime(CLOCK_REALTIME, &ts1);
    sleep(1); // 1 second pause
    // get time2
    clock_gettime(CLOCK_REALTIME, &ts2);
    // nanoseconds difference in mili
    long miliseconds1= (ts2.tv_nsec - ts1.tv_nsec) / 10000000 ;
    // seconds difference in mili
    long miliseconds2 = (ts2.tv_sec -  ts1.tv_sec)*1000;
    long miliseconds = miliseconds1 + miliseconds2;
    printf("%ld\n", miliseconds); 

    return 0;
}

目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community
你说得对,我的回答更多是针对改进AKM Mahmudul Hoque的回答而不是回答原问题。我感到困惑是因为他们给了6分,尽管你的回答显然并没有直接回答问题。 - Alexander Villalba

0

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