linux c/c++ 时间日期操作

总结一下 linux c/c++ 时间相关 API

c-style API

linux 下时间表示类型

  • time_t:表示从 epoch time (1970-01-01 00:00:00 +0000) 到现在的秒数,实际类型为 long int

  • struct timeval:同是 epoch time 距今时间差,最高精度为微秒

    1
    2
    3
    4
    5
    6
    7
    /* A time value that is accurate to the nearest
    microsecond but also has a range of years. */
    struct timeval
    {
    __time_t tv_sec; /* Seconds. */
    __suseconds_t tv_usec; /* Microseconds. */
    };
  • struct timespec:同上,最高精度为纳秒

    1
    2
    3
    4
    5
    struct timespec
    {
    __time_t tv_sec; /* Seconds. */
    __syscall_slong_t tv_nsec; /* Nanoseconds. */
    };
  • struct tm:分解时间,以人类可读的年月日时分秒格式存储

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    struct tm
    {
    int tm_sec; /* 秒 – 取值区间为[0,59] */
    int tm_min; /* 分 - 取值区间为[0,59] */
    int tm_hour; /* 时 - 取值区间为[0,23] */
    int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */
    int tm_mon; /* 月份(从 0 开始,0 代表 1 月) - 取值区间为[0,11] */
    int tm_year; /* 以 1900 年为起始的年份 */
    int tm_wday; /* Day of week. [0-6] */
    int tm_yday; /* Days in year.[0-365] */
    int tm_isdst; /* DST. [-1/0/1]*/

    long int tm_gmtoff; /* Seconds east of UTC. */
    const char *tm_zone; /* Timezone abbreviation. */
    };

时间 API

1
2
time_t time(time_t *t); 
/* 返回 epoch time 到现在经过的秒数 */

以下是 time_t 与分解时间格式 struct tm 之间转换函数:

1
2
struct tm *gmtime (const time_t *__timer) 
/* 将 time_t 格式按照 UTC 时间(即世界协调时)转换成 struct tm 格式 */
1
2
struct tm *localtime (const time_t *__timer);
/* 将 time_t 格式按照本地时区转换成 struct tm 格式 */
1
2
time_t mktime (struct tm *__tp);
/* 将 struct tm 格式转换成 time_t 格式 */

其他获取时间的函数:

1
int gettimeofday (struct timeval *__restrict __tv, void *__restrict __tz);

获取 epoch time 距今的秒数和微秒数。原本第二个参数是可以传一个 struct timezone* 类型的时区参数的,该参数现已废弃,应该传 NULL,该函数本身已是半废弃状态,推荐使用下面的 clock_gettime() 函数

1
int clock_gettime (clockid_t __clock_id, struct timespec *__tp);

获取 __clock_id 所指向的那个系统时钟的时间,精度可达纳秒。根据 linux 手册,第一个参数可指定 8 种时钟类型,这里简单记录几种:

  • CLOCK_REALTIME:实时时钟(墙上时钟),表示自 epoch time 以来的秒数和纳秒数,该时钟既会受系统时间不连续跳跃的影响(比如系统管理员更改了时钟),也会受到增量改变的影响,比如 adjtime() 和 NTP。
  • CLOCK_MONOTONIC:单调时钟,在 Linux 中表示自系统启动以来的时间,不受系统时间不连续跳跃的影响,但会受 ajdtime() 或 NTP 影响。
  • CLOCK_REALTIME_COARSE:功能同 CLOCK_REALTIME,但在牺牲精度的条件下提供了更快的速度。
  • CLOCK_MONOTONIC_COARSE:功能同 CLOCK_MONOTONIC,牺牲精度提高速度。

以下是时间转字符串函数:

1
2
char *ctime (const time_t *__timer);
char *asctime (const struct tm *__tp);

这两个函数都将时间转换成 “Day Mon dd hh:mm:ss yyyy\n” 格式,只不过参数类型不同。调用 ctime(t) 相当于调用 asctime (localtime(t)),即 ctime() 会自动转换本地时区。

1
size_t strftime (char *s, size_t maxsize, const char *format, const struct tm *tp)

将 struct tm 转成格式化时间字符串,详见 reference

c++ chrono

chrono 获取当前时间 (time_t 格式):

1
2
auto const now = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(now);

使用 std::put_time 格式化时间字符串:

1
2
3
4
// time_t new_time
std::stringstream ss;
ss << std::put_time(std::localtime(&now_time), "%R");
std::string time = ss.str();

std::put_time 包含在 <iomanip> 头文件中,具体 format 字符串格式见 reference