C语言再学习 -- 时间函数

C语言再学习 同时被 2 个专栏收录
77 篇文章 40 订阅
58 篇文章 229 订阅

在软件设计中经常会用到关于时间的处理,用来计算语句、函数的执行时间,这时就需要精确到毫秒甚至是微妙的时间。我们首先来介绍一下,时间单位:

时间单位还有:秒(s)、毫秒(ms)、微秒 (μs)、纳秒(ns)、皮秒(ps)、飞秒(fs)、阿秒、渺秒     
1 s = 10^3 ms = 10^6 us = 10^9 ns = 10^12 ps = 10^15 fs=10^18阿秒=10^21渺秒=10^43普朗克常数  


一、首先介绍几个时间函数,

查看:man ctime

NAME  
       asctime,  ctime,  gmtime, localtime, mktime, asctime_r, ctime_r, gmtime_r, localtime_r - transform date and time to broken-down time  
       or ASCII  
  
SYNOPSIS  
       #include <time.h>  
  
       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);  
  
   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):  
  
       asctime_r(), ctime_r(), gmtime_r(), localtime_r():  
              _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || _POSIX_SOURCE  
  
DESCRIPTION  
       The ctime(), gmtime() and localtime() functions all take an argument of data type  time_t  which  represents  calendar  time.   When  
       interpreted as an absolute time value, it represents the number of seconds elapsed since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).  
  
       The  asctime()  and  mktime() functions both take an argument representing broken-down time which is a representation separated into  
       year, month, day, etc.  
  
       Broken-down time is stored in the structure tm which is defined in <time.h> as follows:  
  
           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 */  
           };  

ctime函数:可以把time函数得到的结果转换成一个时间字符串

gmtime函数可以把time函数得到的结果按照格林尼治时间转换成一个结构体

localtime函数:可以把time函数得到的结果按照当前时区转换成一个结构体

asctime函数:可以把一个记录时间的结构体转换成字符串,一般与上两个函数合用的


格林时间,与北京时间换算,参看:TIMEBIE

/* 
    时间函数演示 
 */  
#include <stdio.h>  
#include <time.h>  
int main()  
{  
    time_t tm = 0;//long int别名 //time(0)是一个long int空地址  
    time (&tm);  
    printf ("%s\n", ctime (&tm));  
    struct tm *p_tm = gmtime (&tm);  
    printf ("%s\n", asctime (p_tm));  
    struct tm *p_tm1 = localtime (&tm); //声明语句  
    printf ("%s\n", asctime (p_tm1));  
    return 0;  
}  
输出结果:  
Sat Jan 14 14:48:10 2017  
  
Sat Jan 14 06:48:10 2017  
  
Sat Jan 14 14:48:10 2017  


二、Linux 获取时间戳

第一种方法:微秒级时间戳

查看:man gettimeofday

功能:获取/设置时间

NAME  
       gettimeofday, settimeofday - get / set time  
  
SYNOPSIS  
       #include <sys/time.h>  
  
       int gettimeofday(struct timeval *tv, struct timezone *tz);  
       int settimeofday(const struct timeval *tv, const struct timezone *tz);  
  
   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):  
  
       settimeofday(): _BSD_SOURCE  
  
DESCRIPTION  
       The functions gettimeofday() and settimeofday() can get and set the time as well as a timezone.  The tv argument is a struct timeval  
       (as specified in <sys/time.h>):  
  
           struct timeval {  
               time_t      tv_sec;     /* seconds */  
               suseconds_t tv_usec;    /* microseconds */  
           };  
  
       and gives the number of seconds and microseconds since the Epoch (see time(2)).  The tz argument is a struct timezone:  
  
           struct timezone {  
               int tz_minuteswest;     /* minutes west of Greenwich */  
               int tz_dsttime;         /* type of DST correction */  
           };  
       If either tv or tz is NULL, the corresponding structure is not set or returned.  

下面是个简单的例子,用来统计程序的执行时间:

#include <stdio.h>    
#include <sys/time.h>    
    
int main(void)    
{    
    struct timeval start,end;    
    gettimeofday( &start, NULL );  /*测试起始时间*/    
      
    usleep (10000); //使用 usleep  
      
    gettimeofday( &end, NULL );   /*测试终止时间*/    
  
    int timeuse = (end.tv_usec - start.tv_usec);    
    printf("运行时间为:%d us\n",timeuse);    
    
    return 0;    
    
}   
输出结果:  
10193 us  

第二种方法:毫秒级时间戳,微秒级精度不够
查看:man ftime
功能:返回的日期和时间
NAME
       ftime - return date and time

SYNOPSIS
       #include <sys/timeb.h>

       int ftime(struct timeb *tp);

DESCRIPTION
       This  function  returns  the current time as seconds and milliseconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).  The time is
       returned in tp, which is declared as follows:

           struct timeb {
               time_t         time;
               unsigned short millitm;
               short          timezone;
               short          dstflag;
           };

       Here time is the number of seconds since the Epoch, and millitm is the number of milliseconds since time seconds  since  the  Epoch.
       The  timezone  field  is  the local timezone measured in minutes of time west of Greenwich (with a negative value indicating minutes
       east of Greenwich).  The dstflag field is a flag that, if nonzero, indicates that Daylight Saving time applies  locally  during  the
       appropriate part of the year.

       POSIX.1-2001 says that the contents of the timezone and dstflag fields are unspecified; avoid relying on them.

RETURN VALUE
       This function always returns 0.  (POSIX.1-2001 specifies, and some systems document, a -1 error return.)
tp结构定义:
struct timeb{
  time_t time; /* 为1970-01-01至今的秒数*/
  unsigned short millitm; /* 千分之一秒即毫秒 */
  short timezonel; /* 为目前时区和Greenwich相差的时间,单位为分钟 */
  short dstflag; /* 为日光节约时间的修正状态,如果为非0代表启用日光节约时间修正 */
};
下面是个简单的例子:
#include <stdio.h>  
#include <sys/timeb.h>  
   
long long getSystemTime() {  
    struct timeb t;  
    ftime(&t);  
    return (1000 * t.time + t.millitm) * 1000;  
}  
   
int main() {  
    long long start = getSystemTime();  
    usleep(3000);  
    long long end = getSystemTime();  
   
    printf("time: %lld us\n", end-start);  
    return 0;  
}  
输出结果:
3000 us

第三种方法:秒级时间戳
查看:man difftime    
功能:返回两个time_t型变量之间的时间间隔,即 计算两个时刻之间的时间差。
NAME
       difftime - calculate time difference

SYNOPSIS
       #include <time.h>

       double difftime(time_t time1, time_t time0);

DESCRIPTION
       The  difftime()  function returns the number of seconds elapsed between time time1 and time time0, represented as a double.  Each of
       the times is specified in calendar time, which means its value is a measurement (in  seconds)  relative  to  the  Epoch,  1970-01-01
       00:00:00 +0000 (UTC).
下面是个简单的例子:
#include <stdio.h>  
#include <time.h>  
   
int main(){  
    time_t t_start, t_end;  
    t_start = time(NULL) ;  
    sleep(3);  
    t_end = time(NULL) ;  
    printf("time: %.0f s\n", difftime(t_end,t_start)) ;  
    return 0;  
}  
输出结果:
time: 3 s

第四种方法:C/C++中的计时函数clock()
在MSDN中,查得对clock函数定义如下:
clock_t clock(void) ;
简单而言,就是该程序从启动到函数调用占用CPU的时间。这个函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick)数,在MSDN中称之为挂钟时间(wal-clock);若挂钟时间不可取,则返回-1。其中clock_t是用来保存时间的数据类型

在time.h文件中,我们可以找到对它的定义:
#ifndef _CLOCK_T_DEFINED
typedef long clock_t;
#define _CLOCK_T_DEFINED
#endif
很明显,clock_t是一个长整形数。在time.h文件中,还定义了一个常量CLOCKS_PER_SEC它用来表示一秒钟会有多少个时钟计时单元,其定义如下:
#define CLOCKS_PER_SEC ((clock_t)1000)

在linux系统下,CLOCKS_PER_SEC的值可能有所不同,目前使用的linux打印出来的值是1000000,表示的是微秒。这一点需要注意。
可以看到每过千分之一秒(1毫秒),调用clock()函数返回的值就加1。下面举个例子,你可以使用公式clock()/CLOCKS_PER_SEC来计算一个进程自身的运行时间:
void elapsed_time()
{
printf("Elapsed time:%u secs.\n",clock()/CLOCKS_PER_SEC);
}
当然,你也可以用clock函数来计算你的机器运行一个循环或者处理其它事件到底花了多少时间:
#include"time.h"  
#include"stdlib.h"  
#include"stdio.h"  

void sleep (clock_t wait);  

int main (void)  
{  
  long    i = 600000000L;  
  clock_t start, finish;  
  double  duration;  
  
   
  printf( "延时3秒\n" );  
  sleep( (clock_t)3 * CLOCKS_PER_SEC );  
  printf( "Done!\n" );  
  
   
  start = clock();  
  printf("程序启动,start = %ld\n", start);  

  while( i-- )  
     ;  
  finish = clock();  
  printf("循环结束,finish = %ld\n", finish);  

  duration = (double)(finish - start) / CLOCKS_PER_SEC;  
  printf( "CPU 占用的总时间: %2.1f seconds\n", duration );  
  printf("程序退出...\n");

  return 0; 
}  
  
  
void sleep( clock_t wait )  
{  
  clock_t goal;  
  goal = wait + clock();  
  while( goal > clock() )  
     ;  
}  
输出结果:
延时3秒
Done!
程序启动,start = 3000000
循环结束,finish = 4810000
CPU 占用的总时间: 1.8 seconds
程序退出...

它的另一个功能:利用clock()函数和for循环完成程序定时暂停
#include <stdio.h>
#include<time.h>
int main(void)
{
	int b = 0, i = 0;
	b=clock()/CLOCKS_PER_SEC;
	for(i=0;i<10;)//完成100秒定时
	{
		i = i-b;
		i = clock()/CLOCKS_PER_SEC;
	}
	printf ("finish\n");
	return 0;
}
输出结果:
time ./a.out 
finish

real	0m10.171s
user	0m2.180s
sys	0m7.820s

第五种方法:使用time 命令
最简单的方法了,上面的例子其实已经用到。在执行可执行文件的时候,使用如下命令,便可以统计该程序的运行时间。
time ./a.out 
real	0m10.171s
user	0m2.180s
sys	0m7.820s
time命令,统计的结果包涵程序加载和退出的时间,统计的结果比较粗糙。若想得出函数运行时间较为准确的结果,建议使用上面的几种方法。

三、定时器:

查看:man getitimer

NAME  
       getitimer, setitimer - get or set value of an interval timer  
  
SYNOPSIS  
       #include <sys/time.h>  
  
       int getitimer(int which, struct itimerval *curr_value);  
       int setitimer(int which, const struct itimerval *new_value,  
                     struct itimerval *old_value);  
  
DESCRIPTION  
       The system provides each process with three interval timers, each decrementing in a distinct time domain.  When any timer expires, a  
       signal is sent to the process, and the timer (potentially) restarts.  
  
       ITIMER_REAL    decrements in real time, and delivers SIGALRM upon expiration.  
  
       ITIMER_VIRTUAL decrements only when the process is executing, and delivers SIGVTALRM upon expiration.  
  
       ITIMER_PROF    decrements both when the process executes and when the system is executing on behalf of the  process.   Coupled  with  
                      ITIMER_VIRTUAL,  this  timer  is  usually used to profile the time spent by the application in user and kernel space.  
                      SIGPROF is delivered upon expiration.  
  
       Timer values are defined by the following structures:  
  
           struct itimerval {  
               struct timeval it_interval; /* next value */  
               struct timeval it_value;    /* current value */  
           };  
The function getitimer() fills the structure pointed to by curr_value with the current setting for the timer specified by which (one  
       of  ITIMER_REAL, ITIMER_VIRTUAL, or ITIMER_PROF).  The element it_value is set to the amount of time remaining on the timer, or zero  
       if the timer is disabled.  Similarly, it_interval is set to the reset value.  
  
       The function setitimer() sets the specified timer to the value in new_value.  If old_value is non-NULL, the old value of  the  timer  
       is stored there.  
  
       Timers decrement from it_value to zero, generate a signal, and reset to it_interval.  A timer which is set to zero (it_value is zero  
       or the timer expires and it_interval is zero) stops.  
  
       Both tv_sec and tv_usec are significant in determining the duration of a timer.  
  
       Timers will never expire before the requested time, but may expire some (short) time afterward, which depends on  the  system  timer  
       resolution  and  on  the system load; see time(7).  (But see BUGS below.)  Upon expiration, a signal will be generated and the timer  
       reset.  If the timer expires while the process is active (always true for ITIMER_VIRTUAL) the signal will be  delivered  immediately  
       when generated.  Otherwise the delivery will be offset by a small time dependent on the system loading.  
  
RETURN VALUE  
       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.  

第一个参数:计时器的类型
ITIMER_REAL--真实计时器,主要描述进程运行的真实时间,通过产生SIGALRM信号工作(掌握)
ITIMER_VIRTUAL 虚拟计时器,主要描述进程在用户空间消耗的时间,通过产生SIGVTALRM信号工作(了解)
ITIMER_PROF--实用计时器,主要描述进程在用户空间和内核空间共同消耗的时间,通过产生SIGPROF信号工作(了解)
第二个参数:计时器的新值
struct itimerval 
{
struct timeval it_interval; /* next value */    //间隔时间
struct timeval it_value;    /* current value */ //启动时间
};
struct timeval 
{
long tv_sec;   /* seconds */       //秒数
long tv_usec;  /* microseconds */  //微秒
};
第三个参数:用于获取计时器的旧值,不想带直接给NULL
函数功能:主要用于用户获取/设置计时器的数值


下面是个简单的例子:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/time.h>

void fa(int signo)
{
	printf("贪吃蛇移动了一步\n");
}

int main()
{
	struct itimerval t_start, t_end;
	getitimer (ITIMER_REAL, &t_start);
	printf("Start time: %ld us\n", t_start.it_value.tv_usec);
	
	//设置SIGALRM进行自定义处理
	signal(SIGALRM,fa);

	struct itimerval timer;
	//设置启动时间
	timer.it_value.tv_sec=0;//秒数
	timer.it_value.tv_usec=30000;//微秒
	//设置间隔时间
	timer.it_interval.tv_sec=1;
	timer.it_interval.tv_usec=0;
	//设置真实计时器开始工作
	int res=setitimer(ITIMER_REAL,&timer,NULL);
	if(-1==res)
	{
		perror("settimer"),exit(-1);
	}
	
	getitimer (ITIMER_REAL, &t_end);
	printf("End time: %ld us\n", t_end.it_value.tv_usec);
	
	long cost_time = t_end.it_value.tv_usec - t_start.it_value.tv_usec;
	printf("Cost time: %ld us\n", cost_time);
	while (1);
	return 0;
}
输出结果:
Start time: 0 us
End time: 29997 us
Cost time: 29997 us 
贪吃蛇移动了一步
贪吃蛇移动了一步
贪吃蛇移动了一步
贪吃蛇移动了一步
贪吃蛇移动了一步
^C


扩展:

1、预定义宏里有 __TIME__

__TIME__源文件编译时间,格式为“hh: mm: ss”

#include <stdio.h>  
int main (void)  
{   
    printf ("The time is %s\n", __TIME__);  
    return 0;  
}  
输出结果:   
The time is 18:24:24

2、头文件 time.h
日期和时间函数: 本类别给出时间和日期处理函数
----------------------------------------

下面的函数感兴趣的可以自行百度
时间操作函数得到处理器时间 clock
得到时间差difftime
设置时间mktime
得到时间time
时间转换函数 得到以ASCII码表示的时间asctime
得到字符串表示的时间ctime
得到指定格式的时间strftime

__BEGIN_NAMESPACE_STD
/* Time used by the program so far (user time + system time).
   The result / CLOCKS_PER_SECOND is program time in seconds.  */
extern clock_t clock (void) __THROW;

/* Return the current time and put it in *TIMER if TIMER is not NULL.  */
extern time_t time (time_t *__timer) __THROW;

/* Return the difference between TIME1 and TIME0.  */
extern double difftime (time_t __time1, time_t __time0)
     __THROW __attribute__ ((__const__));

/* Return the `time_t' representation of TP and normalize TP.  */
extern time_t mktime (struct tm *__tp) __THROW;


/* Format TP into S according to FORMAT.
   Write no more than MAXSIZE characters and return the number
   of characters written, or 0 if it would exceed MAXSIZE.  */
extern size_t strftime (char *__restrict __s, size_t __maxsize,
            __const char *__restrict __format,
            __const struct tm *__restrict __tp) __THROW;
__END_NAMESPACE_STD
3、根据文件时间戳的相关属性来查找文件

参看:C语言再学习 -- Linux下find命令用法

我们可以使用 stat 命令来查看一个文件的时间信息,如下:

root@zslf-virtual-machine:/mnt/test# stat ./  
  文件:"./"  
  大小:4096       块:8          IO 块:4096   目录  
设备:801h/2049d   Inode:291601      硬链接:2  
权限:(0755/drwxr-xr-x)  Uid:( 1000/    zslf)   Gid:( 1000/    zslf)  
最近访问:2016-11-25 09:45:24.699140785 +0800  
最近更改:2016-11-25 09:45:22.255140690 +0800  
最近改动:2016-11-25 09:45:22.255140690 +0800  
创建时间:-  

-atime、-mtime、-ctime、-amin、-mmin、-cmin

这里的 -atime、-mtime、-ctime 分别对应的是 “最近一次访问时间”,“最近一次内容修改时间”,“最近一次属性修改时间”,这里的atime的单位指的是“天”,amin 的单位是分钟。


参看:Linux之atime,mtime,ctime

文件的 Access time,atime:是在读取文件或者执行文件时更改的。
文件的 Modified time,mtime: 是在写入文件时随文件内容的更改而更改的。
文件的 Create time,ctime :是在写入文件、更改所有者、权限或链接设置时随 Inode 的内容更改而更改的。 


文件各种事件标记的显示方法

ls -lc filename         列出文件的 ctime 
ls -lu filename         列出文件的 atime 
ls -l filename          列出文件的 mtime  

查看:man ls

-c     with  -lt:  sort  by,  and show, ctime (time of last modification of file status information) with -l: show ctime and sort by
              name otherwise: sort by ctime, newest first

-u     with -lt: sort by, and show, access time with -l: show access time and sort by name otherwise: sort by access time

-l     use a long listing format
查找在五天内没有访问过的文件  
root@zslfe:/mnt/test# find ./ -atime +5  

查找在五天内访问过的文件  
root@zslf:/mnt/test# find ./ -atime -5  
./  
./f.sh  
./g.sh  
./a.sh  
./c.sh  
./b.sh 
4、UNIX时间戳
参看:Linux命令date日期时间和Unix时间戳互转
工具:Unix时间戳转换工具
(1)将日期转换为Unix时间戳
将当前时间以Unix时间戳表示:
# date +%s
1492565563
(2)转换指定日期为Unix时间戳:
# date -d '2013-2-22 22:14' +%s
1361542440
(3)将Unix时间戳转换为日期时间
不指定日期时间的格式:
# date -d @1361542596
Fri Feb 22 22:16:36 CST 2013
(4)指定日期格式的转换:
# date -d @1361542596 +"%Y-%m-%d %H:%M:%S"
2013-02-22 22:16:36


  • 4
    点赞
  • 0
    评论
  • 16
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:猿与汪的秘密 设计师:我叫白小胖 返回首页

打赏作者

聚优致成

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值