如何在Linux的C语言中获取当前时间的毫秒数?

111

如何在Linux上以毫秒为单位获取当前时间?

8个回答

132

可以使用POSIX clock_gettime函数来实现。

在当前版本的POSIX标准中,gettimeofday已被标记为过时。这意味着它可能会在未来的规范版本中被删除。应用程序编写者被鼓励使用clock_gettime函数代替gettimeofday

以下是如何使用clock_gettime的示例:

#define _POSIX_C_SOURCE 200809L

#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <time.h>

void print_current_time_with_ms (void)
{
    long            ms; // Milliseconds
    time_t          s;  // Seconds
    struct timespec spec;

    clock_gettime(CLOCK_REALTIME, &spec);

    s  = spec.tv_sec;
    ms = round(spec.tv_nsec / 1.0e6); // Convert nanoseconds to milliseconds
    if (ms > 999) {
        s++;
        ms = 0;
    }

    printf("Current time: %"PRIdMAX".%03ld seconds since the Epoch\n",
           (intmax_t)s, ms);
}

如果您的目标是测量经过的时间,并且您的系统支持“单调时钟”选项,则应考虑使用CLOCK_MONOTONIC而不是CLOCK_REALTIME


8
+1 以符合 POSIX 标准为好,但是您的回答单位有误。问题提出者需要的不是带有毫秒的时间,而是以毫秒为单位的时间。 - pilcrow
8
好的解决方案,但不要忘记在 gcc 命令中加入 -lm - David Guyon
3
根据round命令的手册,当将结果赋值给整型(或长整型)时,建议使用lround。 - hildred
4
你需要使用floor()而不是round(),这样它就不会四舍五入到1000毫秒。否则,当这种情况发生时,你需要增加s。这可能是一个罕见事件,但额外的数字可能会引起麻烦。 - Mike
3
@SamTebbs33,不应该有任何额外的毫秒。spec.tv_nsec始终小于10亿(因此在四舍五入后,ms永远不会超过1000)。 - Dan Moulding
显示剩余3条评论

69

你需要这样做:

struct timeval  tv;
gettimeofday(&tv, NULL);

double time_in_mill = 
         (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond

39
以下是获取当前时间戳(毫秒级)的实用函数:
#include <sys/time.h>

long long current_timestamp() {
    struct timeval te; 
    gettimeofday(&te, NULL); // get current time
    long long milliseconds = te.tv_sec*1000LL + te.tv_usec/1000; // calculate milliseconds
    // printf("milliseconds: %lld\n", milliseconds);
    return milliseconds;
}

关于时区:

gettimeofday()支持指定时区,我使用了NULL,它会忽略时区,但如果需要,您可以指定一个时区。


@更新 - 时区

由于时间的long表示与时区本身无关,因此设置gettimeofday()tz参数是不必要的,因为它不会产生任何影响。

根据gettimeofday()man页面,使用timezone结构已经过时,因此tz参数通常应该指定为NULL,请参阅man页面获取更多详细信息。


1
支持gettimeofday()指定时区,我使用NULL来忽略时区,但如果需要,您可以指定时区。您是错误的。应该通过调用localtime() 来引入时区。 - vitaly.v.ch
@vitaly.v.ch 我进行了一次测试,将gettimeofday()函数的参数tz设定为&(struct timezone tz = {480, 0})不会报错,且不会影响结果,这是有道理的,因为时间的long表示法与时区本身无关或不受其影响,对吗? - Eric
没有必要进行任何测试。Linux内核没有关于时区的正确信息,同时也没有提供相应的方法。这就是为什么tz参数被以非常特定的方式处理的原因。长表示并不重要。 - vitaly.v.ch
在特定的时间点,长表示不会因为时区而变化,这就是为什么它很重要的原因,因此通常只有NULL是合理的传递值。并且,我相信测试总是证明事情的好方法。 - Eric

13

使用gettimeofday()获取秒和微秒时间。将其组合并舍入到毫秒留作练习。


8

C11 timespec_get

此函数返回精确到纳秒的时间,取决于实现的分辨率。

Ubuntu 15.10已经实现了该函数。API与 POSIX clock_gettime 相同。

#include <time.h>
struct timespec ts;
timespec_get(&ts, TIME_UTC);
struct timespec {
    time_t   tv_sec;        /* seconds */
    long     tv_nsec;       /* nanoseconds */
};

更多细节请参考此处:https://dev59.com/jHRC5IYBdhLWcg3wP-n5#36095407

4

此版本无需数学库,并检查clock_gettime()函数的返回值。

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

/**
 * @return milliseconds
 */
uint64_t get_now_time() {
  struct timespec spec;
  if (clock_gettime(1, &spec) == -1) { /* 1 is CLOCK_MONOTONIC */
    abort();
  }

  return spec.tv_sec * 1000 + spec.tv_nsec / 1e6;
}

2
请说明您的答案相对于其他6个答案的优势(特别是考虑到另外2个答案已经依赖于clock_gettime),并说明它需要哪些头文件以及它如何回答OP的问题。关于CLOCK_MONOTONIC,我建议直接在您的答案(以及您的代码)中使用标准宏,而不是字面量。 - PiCTo
2
虽然这段代码可能回答了问题,但是提供关于为什么和/或如何回答问题的额外上下文可以提高其长期价值。 - Donald Duck

4

根据Dan Moulding的POSIX答案修改得来,这应该可以工作:

#include <time.h>
#include <math.h>

long millis(){
    struct timespec _t;
    clock_gettime(CLOCK_REALTIME, &_t);
    return _t.tv_sec*1000 + lround(_t.tv_nsec/1e6);
}

同样,正如David Guyon所指出的那样:需要使用-lm进行编译。

4
不需要使用浮点数,只需将500K加上并整除1M即可。 - Kevin Thibedeau
感谢您的提示,已修正我的答案。 - Jirka Justra

0
Jirka Justra的答案返回一个长整型,通常为32位。自1970年Unix时间0以来的毫秒数需要更多位,因此数据类型应为long long或unsigned long long,通常为64位。此外,正如Kevin Thibedeau所评论的那样,可以在不转换为浮点数或使用math.h的情况下进行四舍五入。
#include <time.h>
long long millis () {
  struct timespec t ;
  clock_gettime ( CLOCK_REALTIME , & t ) ;
  return t.tv_sec * 1000 + ( t.tv_nsec + 500000 ) / 1000000 ;
}

如果您要测量小于50天的时间,32位就足够了。数据类型int在大多数计算机上是32位或64位,因此数据类型可以是unsigned int。


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