• Linux 下的时间编程总结


          在嵌入式编程中中。常常须要输出系统的当前时间、计算程序的运行时间、使用计时器等。近期也做了不少关于时间的操作。今天就认真总结一下,部分内容是在网上看到的。自己经过验证总结出来。

    1、时间的类型

    1.格林威治标准时间
       coordinated universal time(UTC)是世界标准时间,即常说的格林威治标准时间(greenwich mean time,GMT)。
    2.日历时间
       日历时间(calendar time)是用"一个标准时间点(如1970年1月1日0点)到此时经过的秒数"来表示的时间。

    2、经常使用时间函数的API

    1、获取日历时间

       #include <time.h>
       time_t time(time_t *tloc)
       函数功能 : 获取日历时间,即从1970年1月1日0点到如今所经历的秒数.
       參数 : 通常设置为NULL

     (time_t在time.h中定义:typedef long int time_t)time_t记录自1970年1月1日凌晨以来的秒数,在Linux/Unix上定义为long int类型,在32位系统上,time_t最多仅仅能记录2,147,483,647秒,也就是说到了2038年将会产生溢出(这就是为什么非常多嵌入式设备日期仅仅可以设置到2038年的原因),但在64位系统上不会出现此问题。函数double difftime(time_t time1, time_t time0);用于比較两个time_t类型的值。

    #include <time.h>
     void main()
    {
          long lSeconds = 0;
          lSeconds = time(NULL);
          printf("seconds = %ld
    ", lSeconds);
    }
    

    2、将日历时间转换为格林威治标准时间和本地时间

          通经常使用户得到日历时间的秒数后能够将这些秒数转化为更easy接受的时间表示方式,这些表示时间的方式有格林威治时间、本地时间等首先介绍一个表示时间经常使用的数据结构。

     struct tm
     {
          int tm_sec;   //秒值
          int tm_min;   //分钟值
          int tm_hour;  //小时值
          int tm_mday;  //本月第几日
          int tm_mon;   //本年第几月
          int tm_year;  //tm_year+1900=哪一年
          int tm_wday;  //本周第几日
          int tm_yday;  //本年第几日
          int tm_isdst; //日光节约时间
     }
    -----------------------------------------------------------------
     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)的一个标志。             
    -----------------------------------------------------------------
    函数介绍:

    struct tm *gmtime(const time_t *timep)

     函数功能  : 将日历时间转化为格林威治标准时间。并保存在tm结构
    參数:日历时间的返回值

    struct tm* localtime(const time_t *timep)

     函数功能:将日历时间转化为本地时间,并保存至tm结构
     參数:日历时间的返回值。

    例:

    #include <stdio.h>
    #include <time.h>
    int main(void)
    {
        struct tm *local;
          time_t t;
          t = time(null);       //获取日历时间
          local = localtime(&t);//将日历时间转化为本地时间,并保存在struct tm结构中
          printf("local hour is :%d
    ",local->tm_hour);
          local = gmtime(&t);   //将日历时间转化为格林威治时间。并保存在struct tm结构中
          printf("utc hour is :%d
    ",local->tm_hour);
          return 0;
    }

    3、时间显示

          利用函数gmtime()、localtime()能够将日历时间转化为格林威治时间和本地时间,尽管用户可通过结构体tm来获取这些时间值,但看起来还不方便,最好是将全部的信息。如年、月、日、星期、时、分、秒以字符串的形式显示出来。

    char *asctime(const struct tm *tm)
    函数功能:将tm格式的时间转化为字符串

    參数:日历时间的返回值

    比如: SAT Jul 30 08:43:03 2005

    该函数必须依照以下3个步骤来进行.
       <1>使用函数time()来获取日历时间
       <2>使用函数gmtime()将日历时间转化为格林威治标准时间
       <3>使用函数asctime()将tm格式的时间转化为字符串
    例:

    #include <time.h>
    #include <stdio.h>
    
    int main(void)
    {
          struct tm *ptr;
          time_t lt;
          lt = time(null);        //获取日历时间
          ptr = gmtime(<);        //转化为格林威治时间*/
          printf(asctime(ptr)); //以格林威治时间的字符串方式打印
          printf(ctime(<));     //以本地时间的字符串方式打印*/
          return 0;
    }

    char *ctime(const time_t *timep)
     函数功能:将日历时间转化为本地时间的字符串形式
     參数:日历时间的返回值。

       该函数.必须依照以下2个步骤来进行.
       <1>使用函数time()来获取日历时间
       <2>使用函数ctime()将日历时间直接转化为字符串

    PS:有time函数将time_t值转换为struct tm类型值,函数mktime 能够将struct tm类型值转换为time_t类型的值。其原型为:

    time_t mktime(struct tm *tm);

    4、计算事件耗时

     int gettimeofday(struct timeval *tv, struct timezone *tz)

    函数功能 : 获取从今日凌晨(0:0:0)到如今的时间差。经常使用于计算事件耗时
    參数1 : 存放从今日凌晨(0:0:0)到如今的时间差,时间差以秒或微秒为单位,以结构体形式存放

    參数2 : 常设置为null

    函数使用方法:能够在做某件事情之前调用gettimeofday()。在做完该件事情之后调用gettimeofday(),两个函数的參数1的差就是做该事情所消耗的时间。

    也常常在程序中作为定时器处理,比方每隔多长时间时间运行一次什么事件。

    struct timeval
    {
               int tv_sec;    //秒数
               int tv_usec;   //微秒数
    }

    // 计算时间差。单位毫秒
    int elapsed_time(struct timeval *ct, struct timeval *lt)
    {
    	int elapsed = (ct->tv_sec - lt->tv_sec) * 1000 + (ct->tv_usec - lt->tv_usec) / 1000;
    	return elapsed;
    }

    5、设置系统时钟

    这里要介绍两个函数,同time和gettimeofday相应,stime和settimeofday,原型例如以下:

    int stime(time_t *t);
    int settimeofday(const struct timeval *tv, const struct timezone *tz);
    仅仅是settimeofday设置的时间比stime更精确罢了。

    6、延时函数

    (1)unsigned int sleep(unsigned int seconds)
    函数功能 : 使程序睡眠seconds秒
    參数 : 须要休眠的秒数
    (2)void usleep(unsigned long usec)
    函数功能 : 使程序睡眠usec微秒
    參数 : 须要休眠的秒数

    7、定时器

    unsigned alarm(unsigned seconds);

    #include <stdio.h>
    #include <unistd.h>
    #include <signal.h>
    void alarm_handler(int signum)
    {
    	rintf("Five seconds passed!
    ");
    }
    void func(void)
    {
    	signal(SIGALRM, alarm_handler);
    	alarm(5);
    	pause();
    }  
    int main(void)
    {
    	func();
    	return 0;
    }

          程序将在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 */
    };

    在setitimer函数中,ovalue假设不为空,则保留上次调用设置的值。

    3、时间函数的安全使用方法

          在写代码的时候。常常会用到读取系统时间的函数。

    localtime函数不是线程安全的。假设在多线程里调用localtime函数,非常可能会出现故障。
    多线程应用里面。应该用localtime_r函数替代localtime函数,由于localtime_r是线程安全的。

    相同gmtime函数和gmtime_r函数


    char *asctime(const struct tm *tm);
    char *asctime_r(const struct tm *tm, char *buf);

    char *ctime(const time_t *timep);
    char *ctime_r(const time_t *timep, char *buf);

    struct tm *gmtime(const time_t *timep);
    struct tm *gmtime_r(const time_t *timep, struct tm *result);

    struct tm *localtime(const time_t *timep);
    struct tm *localtime_r(const time_t *timep, struct tm *result);

    time_t mktime(struct tm *tm);

             gmtime() 函数将日历时间timep转换为用UTC时间表示的时间。它可能返回NULL,比方年份不能放到一个整数中。返回值指向一个静态分配的结构,该结构可能会被接下来的不论什么日期和时间函数调用覆盖。gmtime_r()函数功能与此同样,可是它能够将数据存储到用户提供的结构体中。


            localtime() 函数将日历时间timep转换为用户指定的时区的时间。

    这个函数的行为好像是它调用了tzset(3) 而且将外部变量tzname设置为当前时区的信息。将timezone设为UTC和本地标准时间的差值,而且,假设在一年的部分时间使用日光节约规则时将daylight设置为非空值。返回值指向一个静态分配的结构,该结构可能会被接下来的不论什么日期和时间函数调用覆盖。

    localtime_r()函数功能与此同样,可是它能够将数据存储到用户提供的结构体中。它不须要设置tzname


    4、时间函数功能測试

    例1:

    #include <stdio.h>
    #include <time.h>
    int main()
    {
    	time_t cur_time = time(NULL);
    	if (cur_time < 0)
    	{
    		perror("time");
    		return -1;
    	}
    	struct tm utc_tm;
    	if (NULL == gmtime_r(&cur_time, &utc_tm))
    	{
    		perror("gmtime");
    		return -1;
    	}
    	struct tm local_tm;
    	if (NULL == localtime_r(&cur_time, &local_tm))
    	{
    		perror("localtime" );
    		return -1;
    	}
    	printf("UTC = %s", asctime(&utc_tm));
    	printf("LOC = %s", asctime(&local_tm));
    	printf("LOC = %s", ctime(&cur_time));
    	return 0;
    }
    
    输出结果:

    xzg@byxc-PDSML:~/test$ gcc -o time time.c 
    xzg@byxc-PDSML:~/test$ ./time 
    UTC = Tue Jul 15 01:41:08 2014
    LOC = Tue Jul 15 09:41:08 2014
    LOC = Tue Jul 15 09:41:08 2014
    系统时间使用了UTC,能够看到“本地时间= UTC时间 + 8”,输出正确。

    例2:

    #include <stdio.h>
    #include <time.h>
    int main()
    {
    	time_t cur_time = time(NULL);
    	if (cur_time < 0)
    	{
    		perror("time");
    		return -1;
    	}
     
    	struct tm *utc_tm = gmtime( &cur_time );
    	if( NULL == utc_tm )
    	{
    		perror("gmtime" );
    		return -1;
    	}
     
    	<strong>printf("UTC = %s", asctime(utc_tm) );</strong>
     
    	struct tm *local_tm = localtime( &cur_time );
    	if( NULL == local_tm )
    	{
    		perror("localtime" );
    		return -1;
    	}
    	 
    	printf("LOC = %s", asctime(local_tm) );
    	printf("LOC = %s", ctime(&cur_time) );
    	return 0;
    }
    
    输出结果:

    xzg@byxc-PDSML:~/test$ gcc -o time1 time1.c 
    xzg@byxc-PDSML:~/test$ ./time1
    UTC = Tue Jul 15 02:00:38 2014
    LOC = Tue Jul 15 10:00:38 2014
    LOC = Tue Jul 15 10:00:38 2014
    xzg@byxc-PDSML:~/test$ 

    例3:

    #include <stdio.h>
    #include <time.h>
    int main()
    {
    	time_t cur_time = time(NULL);
    	if (cur_time < 0)
    	{
    		perror("time");
    		return -1;
    	}
     
    	struct tm *utc_tm = gmtime( &cur_time );
    	if( NULL == utc_tm )
    	{
    		perror("gmtime" );
    		return -1;
    	}
     
     
    	struct tm *local_tm = localtime( &cur_time );
    	if( NULL == local_tm )
    	{
    		perror("localtime" );
    		return -1;
    	}
            <strong>printf("UTC = %s", asctime(utc_tm) );</strong>
    	printf("LOC = %s", asctime(local_tm) );
    	printf("LOC = %s", ctime(&cur_time) );
    	return 0;
    }
    输出结果:

    xzg@byxc-PDSML:~/test$ gcc -o time1 time1.c 
    xzg@byxc-PDSML:~/test$ ./time1              
    UTC = Tue Jul 15 10:03:26 2014
    LOC = Tue Jul 15 10:03:26 2014
    LOC = Tue Jul 15 10:03:26 2014

             这程序输出有错,UTC时间和本地时间同样了“可能会被接下来的不论什么日期和时间函数调用覆盖”造成的。

    总结:

            使用gmtimelocaltime后要马上处理结果。否则返回的指针指向的内容可能会被覆盖。一个好的方法是使用gmtime_rlocaltime_r,因为使用了用户分配的内存。这两个函数是不会出错的。


  • 相关阅读:
    Foj1675数论
    JSTL与EL之间的千丝万缕
    2013多校联合2 I Warm up 2(hdu 4619)
    ios视图切换之push与present混用
    Ruby设计模式透析之 —— 适配器(Adapter)
    晓说智能指针shared_ptr为何可以实现跨模块分配和释放内存
    CSS的力量
    MySQL-select 1;
    MySQL数据库-语言简介
    Eclipse开发工具提交代码
  • 原文地址:https://www.cnblogs.com/llguanli/p/6958049.html
Copyright © 2020-2023  润新知