1.基本介绍:
对于Linux系统来说:其中的绝对时间表示成新纪元至今经过的秒数,新纪元定义为1970年1月1日00:00:00.下面将介绍有关Linux系统中的时间函数。
2.成员介绍
1).微秒级精确:
#include <sys/time.h>
struct timeval {
time_t tv_sec;/*seconds*/
suseconds_t tv_usec; /* 微秒*/
};
2).原始表示:
Linux时间类中,最简单的数据结构是time_t,在头文件<time.h>中。,其返回的新纪元到至今经过的秒数。如下函数调用获得当前时间。
#include <time.h>
time_t timer=time(NULL);
3).纳秒级别的精度:
因为在一些情况下,毫秒级别的精度还是不够精确。timespec结构体将时间提升到纳秒级别。
#include <time.h>
struct timespec{
time_t tv_sec;/*秒*/
long tv_nsec; /*纳秒*/
};
LINUX系统中,大多数的时间相关的函数都与纳秒有关,所以结构体timeval和timespec两个用的最多。
3.对时间类进行分解
Linux系统中一些函数或者操作需要将时间和字符串进行相互转换,所以有了可以将时间进行分解的结构体 struct tm;
struct tm{
int tm_sec;//秒 0~59
int tm_min;//分钟 0~59
int tm_hour;//小时 0~23
int tm_mday;//天 0~31
int tm_mon;//月 0~11
int tm_year;//年 从1900年以来的年数 一般提取出来+1900
int tm_wday;//以周日以来的天数 0~6
int tm_yday;//从1月1日以来的日期,0~365
int tm_isdet;
long tm_gmtoff;
const char* tm_zone;
};
进程时间类和时间源精度相关的知识不做介绍,因为用的很少。
4.获得当前的时间:
除了调用 time_t time(time_t* ) 函数 还有其他高级调用。
#include <sys/time.h>
int gettimeofday(struct timeval* tv,struct timezone* tz);
该函数调用时会将时间存入tv存入的结构体中,结构体timezone已经废弃,所以传NULL即可。
是失败时返回-1.
与clock相关的函数不过多介绍。
5.设置当前时间:
对于应用程序,有时也需要将当前时间日期设置为一个定值。
#define _SVID_SOURCE
#include <time.h>
int stime(time_t* t);
函数调用时,会设置系统函数时间为t所指向的值并且返回0,调用失败时返回-1,但调用需要define后面的宏
一般情况下只有root用户才有该权限。
#include <sys/time.h>
int settimeofday(const struct timeval* tv,const struct timezone* tz);
成功调用后,会将系统时间设置为tv提供的值,并且返回零。tz参数最好给其提供NULL,调用失败返回-1.
struct timeval tv={.tv_sec=0,.tv_usec=0};
int ret=settimeofday(&tv,NULL);
6.时间类的转换:
gmtime()函数会将time_t转换为tm结构体,通过UTC时区格式表示
#include <time.h>
struct tm* gmtime (const time_t * timep);
struct tm* gmtime_r (const time_t* timep,struct tm* result);
调用失败,返回NULL
函数一是返回静态分配的结构体指针,所以线程不安全,
函数二对于线程是安全的,其操作结果在第二个参数上。
localtime和gmtime类似 但是是通过用户时区显示。
#include <time.h>
struct tm* localtime (const time_t * timep);
struct tm* localtime_r (const time_t* timep,struct tm* result);
调用失败,返回NULL
函数一是返回静态分配的结构体指针,所以线程不安全,
函数二对于线程是安全的,其操作在第二个参数上。
difftime会返回两个time_t值的秒数差,并且强转为double.
#include <time.h>
double difftime(time_t time1,time_t time2);
(double)(time1-time2) 是前减后
7.睡眠和等待;
LINUX系统中的睡眠函数有秒,微秒.
#include <unistd.h>
以秒睡眠
unsigned int sleep(unsigned int seconds);
以微秒进行睡眠
void usleep(unsigned long usec);
unsigned int usec=200;
usleep(usec);
对于纳秒时间来睡眠用的比较少,所以不过多介绍了。
8.定时器:
一般来说,Linux定时器一般与发送信号绑定在一起,下面介绍相关用的比较多的两个函数。
1).alarm函数
#include <unistd.h>
#include <signal.h>
int alarm(int seconds);
发起调用后,此函数会在seconds后将SIGALRM信号发送给进程,
若先前信号未处理,调用就取消该信号,用新的信号覆盖它,
一般成功发送处信号,就需要为信号注册一个信号处理函数,
可以用struct sigaction结构体和sigaction()函数进行封装,或者调用signal()函数
void alarm_handler(int sig){
printf("five second passed!\n");
}
void func(){
sigal(SIGALRM,alarm_handler);
alarm(5);
}
注意一次进程/线程进行只能调用一次alarm()函数,alarm()函数不能重启
2).setitimer()函数:
#include <sys/time.h>
int setitimer(int which,const struct itimerval* value,struct itimerval* ovalue);
和alarm类似,但是此函数能重启,其有三种工作方式,作者只说明 “以测量真实时间”的工作方式。
以测量真实时间,第一个参数要指定 ITIMER_REAL。
itimerval结构体指定用户设置定时器过期或终止的时限,如果设定了值,则在过期后重启定时器。
struct itimerval{
struct timeval it_interval; //发送完信号后,经过it_interval后重启函数调用。
struct timeval it_value; // 函数调用后,经过it_value时间发送SIGALRM信号
};
这就说明发送SIGALRM信号的间隔为 it_interval+it_value,若定时器失败且it_interval=0;,
则不会重启定时器,it_value被设置为0,也不会发送信号。
,in_interval=0且it_value!=0,就是周期性的alarm()函数
若函数的第三个参数不为NULL,则储存定时器的前一个值。调用成功,函数返回零
#include <signal.h>
#include <sys/time.h>
void alarm_handler(int sig){
printf(" passed over!\n");
}
void foo(void){
struct itimerval dealy;
int ret=0;
signal(SIGALRM,alarm_handler);
dealy.it_value.tv_sec=5;
dealy.it_value.tv_usec=0;
dealy.it_interval.tv_sec=1;
dealy.it_interval.tv_usec=0;
ret=setitimer(ITIMER_REAL,&dealy,NULL);
if(ret){
perror("error");
return ;
}
pause();
}
但要注意alarm()函数和setitimer()函数不要混用。