(一)前言
说起time,一般有两种,一个是计时,一个是定时.
最近学APUE看到时间和日期这部分,想起muduo书中的实现规则:
1.计时使用gettimeofday(2)来获取当前时间
原因在于比time有更好的精度,比clock_gettime有更小的开销
2.定时使用timerfd_*系列函数来处理定时任务
原因在于可以拿到一个fd放到Reactor中统一管理,并且不像sleep那样产生异步信号,
书中提到可以个用epoll/poll等的timeout参数来指定超时时间,从而实现定时任务,当时并不知道实现原理,
前段时间看Libevent的Timer实现就明白了,在Libevent中,维护一个时间的小根堆,来管理多个超时事件
这又让我想起更早些的一次面试,当时问如何管理定时事件,我说道timerfd,不过面试官好像并不知道这个timerfd的存在,然后把epoll timeout解释给我..
(二)常用时间类型
time_t
struct tm
struct timeval
struct timespec
1.1 time_t
time_t
实际是一个长整型:
// time.c
#include <time.h>
#include <stdio.h>
int main()
{
time_t t;
return 0;
}
终端输入: gcc -E time.c | grep __time_t
查看结果:
typedef long int __time_t;
typedef __time_t time_t;
time_t实际是一个长整型。其值表示为从UTC(coordinated universal time)时间1970年1月1日00时00分00秒(也称为Linux系统的Epoch时间)到当前时刻的秒数。
#include <time.h>
time_t time(time_t *calptr);
//将返回当前的时间
1.2 struct tm
struct tm {
int tm_sec; /* seconds */
int tm_min; /* minutes */
int tm_hour; /* hours */
int tm_mday; /* day of the month */
int tm_mon; /* month */
int tm_year; /* year */
int tm_wday; /* day of the week */
int tm_yday; /* day in the year */
int tm_isdst; /* daylight saving time */
};
localtime
和gmtime
将日历时间转换成分解的时间,存放在struct tm
中
#include <time.h>
struct tm*gmtime(const time_t *calptr);
struct tm*localtime(const time_t *calptr);
gmtime
返回格林时间、localtime
会返回本地时间,例如返回北京时间
有意思的事情是,time
得到是从1970年开始经过的秒数,不过这个结构体中的成员是从1900年算起
只得到这个结构体是无法知道当前确切的时间,通过char *asctime(const struct tm *tm);
可以将这个结构体可视化出来:
#include <time.h>
#include <stdio.h>
int main()
{
time_t t;
time(&t);
printf("%ld\r\n",t);
struct tm* tt=gmtime(&t);//格林时间
struct tm* localtt=localtime(&t);//北京时间
printf("gm time: %s\r\n",asctime(tt));
printf("local time: %s\r\n",asctime(localtt));
printf("sec: %d\r\n",tt->tm_sec);
printf("min: %d\r\n",tt->tm_min);
printf("hour: %d\r\n",tt->tm_hour);
printf("mday: %d\r\n",tt->tm_mday);
printf("mon: %d\r\n",tt->tm_mon);
printf("year: %d\r\n",tt->tm_year);
printf("wday: %d\r\n",tt->tm_wday);
printf("yday: %d\r\n",tt->tm_yday);
return 0;
}
asctime(localtime(&t))
的效果就相当于ctime(&t)
1.3 struct timeval
对应的函数是gettimeofday
,APUE上说SUSv4指定该函数已经放弃使用,不过我依稀记得我本科毕业设计用它来计算程序运行的时间。 gettimeofday
的优势在于可以返回更高的精度(可到微秒级),封装在结构体中:
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
1.4 struct timespec
对应函数
#include <sys/time.h>
int clock_gettime(clockid_t clock_id, struct timespec *tsp);
当ID设置为CLOCK_REALTIME
时,clock_gettime
将提供与time函数相似的功能,不过在系统支持高精度时间值的情况下,该函数提供纳米级别精度。
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
(三)系统调用
上文中提到的系统调用有time()、ctime()、gmtime()、localtime()、asctime()、gettimeofday()
除此之外,用strftmie
可以格式化时间输出:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int
main(void)
{
time_t t;
struct tm *tmp;
char buf1[16];
char buf2[64];
time(&t);
tmp = localtime(&t);
if (strftime(buf1, 16, "time and date: %r, %a %b %d, %Y", tmp) == 0)
printf("buffer length 16 is too small\n");
else
printf("%s\n", buf1);
if (strftime(buf2, 64, "time and date: %r, %a %b %d, %Y", tmp) == 0)
printf("buffer length 64 is too small\n");
else
printf("%s\n", buf2);
exit(0);
}
(四)参考
1.apue
2.
3.linux多线程编程(陈硕)