前言
我们在linux平台进行开发时,时间相关的操作基本上都会遇到,本文就对常用的时间相关的结构体、接口进行分析小结。
常见类型、结构体定义
timespec
原型
struct timespec
{
__time_t tv_sec;
__syscall_slong_t tv_nsec;
};
说明
该结构体只是包括秒和纳秒,并没有任何其他含义,比如1970年以来的秒数等。只是个存放空间。为clock_gettime的出参。
clock_gettime
原型
int clock_gettime (clockid_t __clock_id, struct timespec *__tp);
说明
根据clock_id(系统时钟)的类型,获取当前时间。
参数说明
clock_id常用取值枚举说明
枚举值 | 说明 |
---|
CLOCK_REALTIME | 系统当前时间,从1970年1月1日算起 | CLOCK_MONOTONIC | 从系统启动时间算起,经过的时间 | CLOCK_PROCESS_CPUTIME_ID | 本进程运行时间 | CLOCK_THREAD_CPUTIME_ID | 本线程运行的时间 |
程序示例
#include <time.h>
#include <stdio.h>
#include <sys/time.h>
int main(void)
{
struct timespec tsp;
printf("CLOCK REALTIME time:\n");
clock_gettime(CLOCK_REALTIME, &tsp);
printf("sec:%ld, nsec:%ld\n", tsp.tv_sec, tsp.tv_nsec);
printf("-----------------------\n");
printf("CLOCK MONOTONIC time:\n");
clock_gettime(CLOCK_MONOTONIC, &tsp);
printf("sec:%ld, nsec:%ld\n", tsp.tv_sec, tsp.tv_nsec);
printf("-----------------------\n");
printf("CLOCK PROCESS CPUTIME ID time:\n");
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tsp);
printf("sec:%ld, nsec:%ld\n", tsp.tv_sec, tsp.tv_nsec);
printf("-----------------------\n");
printf("CLOCK THREAD CPUTIME ID time:\n");
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tsp);
printf("sec:%ld, nsec:%ld\n", tsp.tv_sec, tsp.tv_nsec);
printf("-----------------------\n");
return 0;
}
运行结果:
CLOCK REALTIME time:
sec:1644155596, nsec:748701786
-----------------------
CLOCK MONOTONIC time:
sec:12526311, nsec:817330221
-----------------------
CLOCK PROCESS CPUTIME ID time:
sec:0, nsec:585929
-----------------------
CLOCK THREAD CPUTIME ID time:
sec:0, nsec:590570
timeval
原型
struct timeval
{
__time_t tv_sec;
__suseconds_t tv_usec;
};
说明
该结构体只是包括秒和微秒,并没有任何其他含义,比如1970年以来的秒数等。只是个存放空间。为gettimeofday的出参。
timezone
原型
struct timezone
{
int tz_minuteswest;
int tz_dsttime;
};
说明
该结构体为时区相关信息,用的比较少,gettimeofday的出参。一般我们也可以直接传入NULL.
gettimeofday
原型
int gettimeofday(struct timeval *tv, struct timezone *tz);
说明
获取当前时间,为UTC时间,1970年以来的秒+微秒、时区信息。
参数说明
参数 | 类型 | 说明 |
---|
tv | struct timeval * | 出参,当前UTC时间 | tz | struct timezone * | 当前时区信息 |
返回值
成功则返回0,失败则返回-1,错误原因存在errno中。
程序示例
#include <time.h>
#include <stdio.h>
#include <sys/time.h>
int main(void)
{
struct timeval tv;
struct timezone tz;
printf("gettimeofday time:\n");
gettimeofday(&tv, &tz);
printf("tv_sec:%ld tv_usec:%ld\n", tv.tv_sec, tv.tv_usec);
printf("tz:%d %d\n", tz.tz_dsttime, tz.tz_minuteswest);
return 0;
}
运行结果:
gettimeofday time:
tv_sec:1644156383 tv_usec:513679
tz:0 0
time_t
原型
typedef long time_t;
说明
该类型其实就是long int ,用于存储秒数,是time函数的入参和返回值。
time
原型
time_t time(time_t *t)
说明
该函数会返回从1970年1月1日0时0秒算起到现在所经过的秒数,如果t为非空指针的话,该函数还会将返回值存储到t指针所指的内存里。
参数说明
返回值
成功则返回秒数,失败则返回-1,错误原因存在errno中。
程序示例
#include <time.h>
#include <stdio.h>
#include <sys/time.h>
int main(void)
{
time_t timep1, timep2;
timep1 = time(NULL);
time(&timep2);
printf("timep1:%ld timep2:%ld\n", timep1, timep2);
return 0;
}
运行结果:
timep1:1644157011 timep2:1644157011
tm
原型
struct tm
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
说明
该类型用于描述真实世界所使用的时间日期,包括年月日时分秒周等, 是localtime的返回值
localtime
原型
struct tm *localtime(const time_t *timep);
说明
将参数timep所指的当前秒数转换成真实世界所使用的时间日期表示方法,结果返回。
参数说明
返回值
当前UTC秒数对应的年月日时分秒周等。
程序示例
#include <time.h>
#include <stdio.h>
#include <sys/time.h>
int main(void)
{
time_t timep;
struct tm *p;
timep = time(NULL);
printf("timep:%ld\n", timep);
p = localtime(&timep);
printf("%d-%d-%d %d:%d:%d \n", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday,
p->tm_hour, p->tm_min, p->tm_sec);
return 0;
}
运行结果:
timep:1644157741
2022-2-6 22:29:1
localtime_r
在上面localtime的程序示例中,可以发现,localtime的返回值是 struct tm *类型,也就是指向struct tm类型的指针,这样使用并不会造成内存泄露等问题,这是因为localtime的返回值其实指向了一个静态变量,这是静态库已经定义的static struct tm类型数据,很明显,由于程序使用静态变量,会导致localtime不可重入,也就是非现成安全,对于一般的应用场景并不会带来什么隐患,但是对于实时性要求高的场所,会带来问题,因为多次调用localtime会造成返回值覆盖。
比如:
两个线程A和B同时调用 localtime 函数:
时刻1:线程A调用 localtime 函数,得到一个指针,tm中存储的值更新为 value-A
时刻2:线程B调用 localtime 函数,得到一个指针, tm中存储的值更新为 value-B
时刻3:线程A对 localtime 返回的指针进行相关引用操作(例如 printf 输出某字段),此时 static struct tm 中的值实际是 value-b,并非预期的 value-a
时刻4:线程B对 localtime 返回的指针进行相关引用操作,此时 static struct tm 中的值实际是 value-b
所以为了解决localtime不可重入的问题,就出现了localtime_r。
原型
struct tm *localtime_r(const time_t *timep, struct tm *result);
说明
调用 localtime 只需要传入指向 time_t 的一个常量指针;
调用 localtime_t 不仅需要传入指向 time_t 的一个常量指针,还需要传入指向 struct tm 的一个指针,结果将存储在 result 指向的 struct tm 对象中;
程序示例
#include <time.h>
#include <stdio.h>
#include <sys/time.h>
int main(void)
{
time_t timep;
struct tm *p;
struct tm res;
timep = time(NULL);
printf("timep:%ld\n", timep);
localtime_r(&timep, &res);
printf("%d-%d-%d %d:%d:%d \n", 1900 + res.tm_year, 1 + res.tm_mon, res.tm_mday,
res.tm_hour, res.tm_min, res.tm_sec);
return 0;
}
运行结果:
timep:1644158806
2022-2-6 22:46:46
小结
以上为linux平台下,与时间相关的常用结构体、变量、接口定义,再详细的说明可以参考相关源码定义。
|