Linux C/C++ 获取系统时间
概述
C 标准库提供了 time()
函数与 localtime()
函数可以获取到当前系统的日历时间,但 time()
函数精度只能到秒级,如果需要更高精度的系统时间需要使用 gettimeofday()
函数,精度达到微秒级。
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
tv
参数是一个 struct timeval
结构体(同样是在 <sys/time.h>
头文件中定义):
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
时区结构体 struct timezone
的使用已过时,tz
参数通常应指定为 NULL。
函数 localtime()
把 timep
指向的日历时间转换为表示本地时间的细分时间。
#include <time.h>
struct tm *localtime(const time_t *timep);
localtime()
返回一个指向 struct tm
对象的指针,它保存了一个日历时间的各组成部分,日历时间也被称为细分时间(Broken-down time)。该结构体定义在 <time.h>
头文件中:
struct tm {
int tm_sec; /* Seconds (0-60) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */
int tm_year; /* Year - 1900 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};
tm
结构体的成员:
- tm_sec —— 分钟后的秒数,通常在 59 秒的范围内,但最多可以达到 60 秒,以允许闰秒。
- tm_min —— 小时后的分钟数,范围为 0 到 59。
- tm_hour —— 午夜过后的小时数,范围为 0 到 23。
- tm_mday —— 一个月的某一天,范围为 1 到 31。
- tm_mon —— 自 1 月以来的月份数,范围为 0 到 11(显示月份的时候需要加 1)
- tm_year —— 自 1900 年以来的年数(显示年份的时候需要加上 1900)
- tm_wday —— 自周日(星期日)以来的天数,范围为 0 到 6。
- tm_yday —— 自 1 月 1 日以来的天数,范围为 0 到 365。
- tm_isdst —— 指示夏时制在所述时间是否有效的标志。如果夏令时有效,则该值为正值;如果夏令时无效,则为零;如果信息不可用,则为负值。
示例
#include <stdio.h> // included for 'printf()'
#include <sys/time.h> // included for 'gettimeofday()'
#include <time.h> // included for 'localtime()'
int main(int argc, char const *argv[]) {
struct timeval tv;
gettimeofday(&tv, NULL);
time_t sec = tv.tv_sec;
suseconds_t usec = tv.tv_usec;
struct tm *lt = localtime(&sec);
printf("%d-%02d-%02d %02d:%02d:%02d.%03d\n",
lt->tm_year + 1900,
lt->tm_mon + 1,
lt->tm_mday,
lt->tm_hour,
lt->tm_min,
lt->tm_sec,
(int)(usec / 1000));
return 0;
}
使用 gettimeofday
获取到保存在 timeval
结构体的时间之后,通过 localtime
函数将 tv_sec
转换成 struct tm
结构体,在关键的 tm_year
, tm_mon
进行特殊处理计算出当前到秒的日历时间,然后通过将 tv_usec
微秒数除以 1000 得到毫秒数。
在命令行使用 gcc
编译:
gcc -o main main.c
结果为带毫秒数的当前日历时间:
$ ./main
2022-12-15 11:03:56.847
易用性封装
如果需要直接在代码中获取当前带毫秒数的日历时间,可以参考以下封装接口:
使用 C++11 标准的 thread_local
创建一个线程安全的全局变量,然后将运算结果存储在全局变量中,最后返回对象的指针,这样既能保证调用函数的易用性,同时也能兼顾运算性能,这种写法可以非常简单地应用到大部分应用中:
thread_local char __timebuf[64] = {0x00};
const char *curtime() {
struct timeval tv;
gettimeofday(&tv, NULL);
struct tm *lt = localtime(&tv.tv_sec);
snprintf(__timebuf, sizeof(__timebuf) - 1,
"%d-%02d-%02d %02d:%02d:%02d.%03d",
lt->tm_year + 1900,
lt->tm_mon + 1,
lt->tm_mday,
lt->tm_hour,
lt->tm_min,
lt->tm_sec,
(int)(tv.tv_usec / 1000));
return __timebuf;
}
△ \triangle △ Linux C/C++ 单实例进程设计