文先生的博客 求职,坐标深圳。(wenfh2020@126.com)

gettimeofday 获取本地时间

2020-08-04

获取本地时间是比较常用的操作,可通过 gettimeofday 函数获取本地时间,然后根据需要转化成对应的时间单位:毫秒,微秒,秒。


1. gettimeofday

1
2
3
4
5
6
7
8
#include <sys/time.h>

int gettimeofday(struct timeval *tp, struct timezone *tzp);

struct timeval {
    time_t       tv_sec;   /* seconds since Jan. 1, 1970 */
    suseconds_t  tv_usec;  /* and microseconds */
};

2. 单位

2.1. 毫秒

1
2
3
4
5
6
7
8
9
long long mstime() {
    struct timeval tv;
    long long mst;

    gettimeofday(&tv, NULL);
    mst = ((long long)tv.tv_sec) * 1000;
    mst += tv.tv_usec / 1000;
    return mst;
}

2.2. 微秒

1
2
3
4
5
6
7
8
9
10
long long ustime() {
    struct timeval tv;
    long long ust;

    gettimeofday(&tv, NULL);
    ust = ((long)tv.tv_sec) * 1000000;
    ust += tv.tv_usec;
    return ust;
}


2.3. 秒(double)

1
2
3
4
5
double time_now() {
    struct timeval tv;
    gettimeofday(&tv, 0);
    return ((tv).tv_sec + (tv).tv_usec * 1e-6);
}

3. 格式化

[年]-[月]-[日] [时]-[分]-[秒].[毫秒]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <sys/time.h>
#include <unistd.h>
#include <iostream>

void format() {
    int off;
    time_t t;
    char buf[64];
    struct tm* tm;
    struct timeval tv;

    t = time(NULL);
    tm = localtime(&t);
    gettimeofday(&tv, NULL);

    /* 时间精度:秒。 */
    off = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm);
    std::cout << "[" << buf << "]" << std::endl;

    /* 时间精度:毫秒。 */
    snprintf(buf + off, sizeof(buf) - off, ".%03d", (int)tv.tv_usec / 1000);
    std::cout << "[" << buf << "]" << std::endl;
}

int main() {
    format();
    return 0;
}
1
2
3
# g++ test_time.cpp -o test_time && ./test_time
[2020-10-16 10:07:22]
[2020-10-16 10:07:22.916]

4. c++11 时间接口

c++11 提供了时间获取接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <chrono>
#include <iostream>

int main() {
    auto t1 = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 10000000; i++) {
        std::chrono::high_resolution_clock::now();
    }
    auto t2 = std::chrono::high_resolution_clock::now();
    auto spend_s = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);
    auto spend_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
    std::cout << "spend: " << spend_s.count() << " s"
              << std::endl
              << "spend: " << spend_ms.count() << " ms"
              << std::endl;
    return 0;
}

5. 性能

5.1. 问题

高并发系统里,从火焰图里看到:平平无奇的 mstime() 接口,却是资源吃货!

火焰图参考:如何生成火焰图🔥


5.2. 优化

一般业务,对时间精度要求不高。可以按照两个方面优化:

  • 放在时钟里定时设置。
  • 根据使用频率设置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Network {
    ...
protected:
    int m_time_index = 0;
    uint64_t m_now_time = 0;

    void on_repeat_timer() {
         m_now_time = mstime();
    }

    uint64_t now() {
        if ((++m_time_index % 10) == 0) {
            m_now_time = mstime();
        }
        return m_now_time;
    }
    ...
};

有空的朋友,可以阅读一下 libev 的源码,看看它是怎么获取当前时间的。

1
2
3
ev_tstamp ev_now (struct ev_loop *loop) {
  return ((loop)->ev_rt_now);
}

作者公众号
微信公众号,干货持续更新~