Linux时间编程

来源:互联网 发布:惠州综合网络问政平台 编辑:程序博客网 时间:2024/06/13 22:41

1. time_t

time_t记录自1970年1月1日凌晨以来的秒数,在Linux/Unix上定义为long int类型,在32位系统上,time_t最多只能记录2,147,483,647秒,也就是说到了2038年将会产生溢出,但在64位系统上不会出现此问题。

time_t time(time_t *t);
例子如下:
[cpp] view plain copy
  1. #include <stdio.h>  
  2. #include <time.h>  
  3.   
  4. int main(void)  
  5. {  
  6.         time_t sec;  
  7.   
  8.         sec = time(NULL);  
  9.   
  10.         printf("%ld\n", sec);  
  11.   
  12.         return 0;  
  13. }  
time函数返回自1970年1月1日凌晨以来的秒数,参数t可以为NULL。同时还提供了一个函数difftime,原型如下:
double difftime(time_t time1, time_t time0);
用于比较两个time_t类型的值。

2. struct tm
由time_t可以知道,操作系统使用的是long int类型的值来存储时间,但对于用户来说肯定是不好理解,所以就有了这里的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 */};----------------------------------------------------------------- tm_sec         |       秒,范围是0~59。                         tm_min         |       分,范围是0~59。                         tm_hour        |       时,范围是0~23。                         tm_mday        |       日,范围是1~31。                         tm_mon         |       月,范围是0~11,注意是0到11。            tm_year        |       年,自1900以来的年数。                   tm_wday        |       星期几,从星期天开始计算,范围是0~6。 tm_yday        |       一年中的哪一天,0~365。                  tm_isdst       |       夏令时间(DST)的一个标志。             -----------------------------------------------------------------

那怎么能得到这个时间呢,有两个函数gmtime和localtime,原型如下:
struct tm *gmtime(const time_t *timep);struct tm *localtime(const time_t *timep);
例子如下:
[cpp] view plain copy
  1. #include <stdio.h>  
  2. #include <time.h>  
  3.   
  4. int main(void)  
  5. {  
  6.         const char *const days[] = {"星期天""星期一""星期二",  
  7.                                 "星期三""星期四""星期五""星期六"};  
  8.         time_t sec;  
  9.   
  10.         struct tm *n;  
  11.   
  12.         sec = time(NULL);  
  13.   
  14.         n = localtime(&sec);  
  15.   
  16.         printf("%d年 %d月 %d日 %s %d:%d:%d\n",  
  17.                         n->tm_year + 1900,  
  18.                         n->tm_mon + 1,  
  19.                         n->tm_mday,  
  20.                         days[n->tm_wday],  
  21.                         n->tm_hour,  
  22.                         n->tm_min,  
  23.                         n->tm_sec);  
  24.   
  25.         return 0;  
  26. }  
那么gmtime和localtime两个函数有什么不同的呢,gmtime获取的是UTC时间,localtime获取的是当前系统的时间。

再介绍两个函数,ctime和asctime,原型如下:
char *ctime(const time_t *timep);char *asctime(const struct tm *tm);
例子如下:
[cpp] view plain copy
  1. #include <stdio.h>  
  2. #include <time.h>  
  3.   
  4. int main(void)  
  5. {  
  6.         time_t sec;  
  7.   
  8.         sec = time(NULL);  
  9.   
  10.         printf("%s\n", ctime(&sec));  
  11.   
  12.         return 0;  
  13. }  
上面程序执行结果如下:
Mon Nov 11 17:40:34 2013
也就说ctime函数将time_t类型的值转换为一个时间相关的字符串,而asctime同ctime函数不同的是,asctime的参数为strut tm类型指针,而ctime的参数为time_t类型的指针,只是参数类型不一样,但是结果都是一样的,都是获取一个时间相关的字符串。

//2015.08.12 add

注意:ctime函数的返回的字符串是静态分配的,下次调用ctime函数会将其覆盖,所以在打印时需要注意一下,例如下面这样的打印语句只能得到一个结果值:

[cpp] view plain copy
  1. printf("%s %s", ctime(&time1), ctime(&time2));  

必须分开打印,asctime函数也是一样的。


那既然有time函数将time_t值转换为struct tm类型值,那自然也有将struct tm类型值转换为time_t类型的值,函数为mktime,原型为:
time_t mktime(struct tm *tm);

3. 关于获取和设置系统时钟
前面使用的是time来获取一个时间值,但是它的精度只能达到秒级,如果只是做一个日历足够了,但是如果想获取更精确的时间呢,比如想计算程序的执行时间,显然time函数不能满足我们的要求,那就只能使用这里的gettimeofday函数了,原型如下:
int gettimeofday(struct timeval *tv, struct timezone *tz);
其中struct timeval结构类型定义如下:
struct timeval {
time_t      tv_sec;/* seconds */suseconds_t tv_usec;/* microseconds */};
struct timeval结构类型提供了一个微秒级成员tv_usec,它的类型同样是一个整型类型。
而gettimeofday函数的tz参数用于获取时区信息,在Linux中通常设置为NULL,程序例子如下:
[cpp] view plain copy
  1. #include <stdio.h>  
  2. #include <sys/time.h>  
  3.   
  4. int main(void)  
  5. {  
  6.         struct timeval tv;  
  7.         int ret;  
  8.   
  9.         ret = gettimeofday(&tv, NULL);  
  10.         if (ret) {  
  11.                 perror("gettimeofday");  
  12.         } else {  
  13.                 printf("seconds=%ld useconds=%ld\n",  
  14.                         (long)tv.tv_sec, (long)tv.tv_usec);  
  15.         }  
  16.   
  17.         return 0;  
  18. }  
gettimeofday函数如果获取失败,返回-1值,同时设置errno为EFAULT。

那如何去设置设置系统时钟呢?这里要介绍两个函数,同time和gettimeofday对应,stime和settimeofday,原型如下:
int stime(time_t *t);int settimeofday(const struct timeval *tv, const struct timezone *tz);
只是settimeofday设置的时间比stime更精确罢了。

4. 关于睡眠延时
睡眠延时先介绍两个函数sleep和usleep,原型如下:
unsigned int sleep(unsigned int seconds);int usleep(useconds_t usec);
sleep用于睡眠多少秒,而usleep为睡眠多少微妙。
使用这两个函数需要包含头文件unistd.h。

5. 定时器
alarm函数原型如下:
unsigned alarm(unsigned seconds);
例子如下:
[cpp] view plain copy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <signal.h>  
  4.   
  5. void alarm_handler(int signum)  
  6. {  
  7.         printf("Five seconds passed!\n");  
  8. }  
  9.   
  10. void func(void)  
  11. {  
  12.         signal(SIGALRM, alarm_handler);  
  13.         alarm(5);  
  14.   
  15.         pause();  
  16. }  
  17.   
  18. int main(void)  
  19. {  
  20.         func();  
  21.   
  22.         return 0;  
  23. }  
程序将在5秒之后执行alarm_handler函数,这里还使用了pause函数,用于挂起进程直到捕捉到一个信号时才退出。注意alarm一次只能发送发送一个信号,如果要再次发送信号,需要重新调用alarm函数。

除了alarm外,还可以使用setitimer来设置定时器,使用getitimer来获取定时器的状态,原型如下:
int setitimer(int which, const struct itimerval *restrict value,              struct itimerval *restrict ovalue);int getitimer(int which, struct itimerval *value);
需要包含头文件sys/time.h

which参数有三种取值:
ITIMER_REAL按实际时间记时,时间到了之后发送SIGALRM信号,相当于alarm。ITIMER_VIRTUAL仅当进程执行时才进行记时,发送SIGVTALRM信号。ITIMER_PROF当进程执行时和系统执行该进程时都记时,发送的是SIGPROF信号。

struct itimerval用来指定定时时间,定义如下:
struct itimerval {struct timerval it_interval;/* next value */struct timerval it_value;/* current value */};
struct timeval结构前面都见过了,这里就不再描述了。
在setitimer函数中,ovalue如果不为空,则保留上次调用设置的值。例子如下:
[cpp] view plain copy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <signal.h>  
  4. #include <sys/time.h>  
  5.   
  6. void alarm_handler(int signo)  
  7. {  
  8.         printf("Timer hit!\n");  
  9. }  
  10.   
  11. void foo(void)  
  12. {  
  13.         struct itimerval delay;  
  14.         int ret;  
  15.   
  16.         signal(SIGALRM, alarm_handler);  
  17.   
  18.         delay.it_value.tv_sec = 1;  
  19.         delay.it_value.tv_usec = 0;  
  20.         delay.it_interval.tv_sec = 1;  
  21.         delay.it_interval.tv_usec = 0;  
  22.         ret = setitimer(ITIMER_REAL, &delay, NULL);  
  23.         if (ret) {  
  24.                 perror("setitimer");  
  25.                 return;  
  26.         }  
  27.   
  28.         while (1);  
  29. }  
  30.   
  31. int main(void)  
  32. {  
  33.         foo();  
  34.   
  35.         return 0;  
  36. }  
程序将每隔一秒钟调用一次alarm_handler函数,注意这里将delay.it_interval.tv_sec设置为了1,当it_value中的值减到零时,将产生一个信号,并将it_value的值设置为it_interval,然后又重新开始记时。
0 0