linux时间编程(一) - 获取时间

本文介绍了Linux下的时间编程,包括时间类型如UTC和日历时间,以及获取时间的C语言函数,如`time()`、`gmtime()`、`localtime()`、`ctime()`、`gettimeofday()`等,还提到了高精度的`clock_gettime()`函数和睡眠函数。

自从时间在人类思想中诞生以来,它就作为一个永恒的标杆,竖立在每个人心中。程序员眼中的时间是毫秒级别的,所以这些人在程序中对时间的控制与获取是极为重视的。

linux作为一个维护多年健壮的内核,它对时间的编程也是服务周到的,程序员可以通过一些相关API获取 世界标准时间(UTC),本地时间,系统时间等,也可以通过定时器控制自己的代码运行,而且这些API也有不同时间精度,不同精度适用于不同环境场合,使得linux时间编程更灵活


本帖转自:http://blog.csdn.net/jiebaoabcabc/article/details/36919515


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

二、时间的获取

在程序当中, 我们经常要输出系统当前的时间,比如日志文件中的每一个事件都要记录其产生时间。在 C 语言中获取当前时间的方法有以下几种,它们所获得的时间精度从秒级到纳秒,各有所不同。

 C 时间函数
function 定义 含义 返回值 精度
time() time 函数获得从 1970 年 1 月 1 日 0 点到当前的秒数,存储在time_t结构之中。 time_t
gettimeofday() gettimeofday 函数返回从 1970 年 1 月 1 日 0 点以来,到现在的时间。用 timeval 数据结构表示。 struct timeval
{
time_t tv_sec;
long int tv_usec;
};
微秒
clock_gettime() clock_gettime 函数返回从 1970 年 1 月 1 日 0 点以来,到现在的时间。用 timespec 数据结构表示。
支持不广泛,属于实时扩展,多用于嵌入式linux中。
struct timespec
{
time_t tv_sec;
long int tv_nsec;
};
纳秒
       
三、时间显示和转换

linux提供的时间是一个 从 1970 年 1 月 1 日 0 点以来,到现在的时间秒计数值,如果程序员仅仅要获取直观的年月日形式的时间格式,那么就需要进行转换了。

由于国家,习惯和时区的不同,时间的表示方法并没有一个统一的格式。为了满足各种时间显示的需求,标准 C 库提供了许多时间格式转换的函数。这些函数的数量众多,容易让人迷惑,记住它们的用法十分不易。在这里我借用 Michael Kerrisk 在《Linux Programming Interface》一书中的插图,来对这些标准 C 函数进行一个总体的概览。

图 1. 各种时间显示格式转换函数关系图
各种时间显示格式转换函数关系图

通过这幅图应该能很直观的看到linux时间格式转换的流程。

四、时间函数的API

时间函数的API均属于系统调用函数.。

1.获取日历时间
  #include <time.h>// Glibc
  time_t time(time_t *t)// 获取时间

   函数功能: 获取日历时间,即从1970年1月1日0点到现在所经历的秒数.
   参数: 通常设置为NULL,也可以通过传入time_t类型变量的地址来获取时间

time_t stime(const time_t *when)// 设置时间

   函数功能: 设置日历时间,即从1970年1月1日0点到现在所经历的秒数.
    参数: 通常通过strptime->mktime->stime自定义格式时间格式设置时间

time_t在time.h中定义:typedef long int time_t)
   例:

#include <stdio.h>
   #include <time.h>
   void main()
   {
      long int seconds=0;
      seconds = time(NULL);
      printf("seconds=%d\n",seconds);
   }


2.将日历时间转换为格林威治标准时间

   struct tm *gmtime(const time_t *timep)
   函数功能:将日历时间转化为格林威治标准时间,并保存在tm结构
   参数:日历时间的返回值


3.将日历时间转化为本地时间
   struct tm* localtime(const time_t *timep)
   函数功能:将日历时间转化为本地时间,并保存至tm结构
   参数:日历时间的返回值


   由上面两个函数可以看出,这两个函数的返回值均存放在tm结构中,具体的tm结构如下:

   	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; //日光节约时间
   	}


4.时间显示

   char *asctime(const struct tm *tm)
   函数功能:将tm格式的时间转化为字符串
   参数:日历时间的返回值
   例如: SAT Jul 30 08:43:03 2005

该函数较ctime()使用起来更加的复杂.必须按照下面3个步骤来进行.
   <1>使用函数time()来获取日历时间
   <2>使用函数gmtime()将日历时间转化为格林威治标准时间
   <3>使用函数asctime()将tm格式的时间转化为字符串

#include <stdio.h>
#include <time.h>

int main ()
{
	time_t time_raw_format;
	struct tm * time_struct;
	char buf [64];
	
	time ( &time_raw_format );
	// gmtime : time_t -> tm 此函数返回的时间日期未经时区转换,而是UTC时间
	time_struct = gmtime ( &time_raw_format );
	// mktime : tm -> time_t
	mktime(&time_raw_format);
	
	// asctime : tm -> time string  string have a '\n'
	printf("%s", asctime(time_struct));
	// strftime : tm -> user time string   It is now: 04:27PM.
	strftime (buf,64,"It is now: %I:%M%p.",time_struct);
	// strptime : user time string -> tm  set time
	//strptime("2000-01-01-00:00:00",  "%Y-%m-%d-%H:%M:%S", time_struct);
	puts (buf);
	return 0;
}

   char *ctime(const time_t *timep)
   函数功能:将日历时间转化为本地时间的字符串形式
   参数:日历时间的返回值
   该函数较asctime()使用起来更加简单.必须按照下面2个步骤来进行.
   <1>使用函数time()来获取日历时间
   <2>使用函数ctime()将日历时间直接转化为字符串

#include <stdio.h>
#include <time.h>

int main ()
{
	time_t time_raw_format;
	
	time ( &time_raw_format ); //获取当前时间
	printf (" time is [%d]\n", time_raw_format);
	//用 ctime 将时间转换为字符串输出
	printf ( "The current local time: %s\n", ctime(&time_raw_format));
	// stime set time
	printf ( "The current local time: %s\n", stime(&time_raw_format));
	return 0;
}


5.获取从今日凌晨到现在的时间差

 int gettimeofday(struct timeval *tv,struct timezone *tz)
   函数功能:获取从今日凌晨(0:0:0)到现在的时间差,常用于计算事件耗时
   参数1:存放从今日凌晨(0:0:0)到现在的时间差,时间差以秒或微秒为单位,以结构体形式存放
         struct timeval
        {
           int tv_sec;    //秒数
           int tv_usec;   //微秒数
        }
   参数2:常设置为null
   函数用法:可以在做某件事情之前调用gettimeofday(),在做完该件事情之后调用gettimeofday(),两个函数的参数1的差就是做该事情所消耗的时间.

#include <stdio.h>
#include <time.h>
#include <math.h>	// -lm
#include <sys/time.h>	// timeval gettimeofday
#include <stdlib.h>	// exit

float
measureTime(struct timeval *start, struct timeval *stop);

void function() 
{ 
	unsigned int i,j; 
	double y; 
	
	for(i=0;i<1000;i++) 
		for(j=0;j<1000;j++) 
			y=sin((double)i); //耗时操作
} 

int main() 
{ 
	struct timeval tpstart,tpend; 
	float timeuse; 

	gettimeofday(&tpstart,NULL); //记录开始时间戳
	function(); 
	gettimeofday(&tpend,NULL); //记录结束时间戳

	timeuse = measureTime(&tpstart, &tpend);

	printf("Used Time:%f\n",timeuse); 
	exit(0); 
}


float
measureTime(struct timeval *start, struct timeval *stop)
{
	float timeuse;
	
	timeuse = 1000000*(stop-> tv_sec - start-> tv_sec)+ 
				stop-> tv_usec - start-> tv_usec; //计算差值
				
	return timeuse /= 1000000; 	// sec
}

由于用到了数学函数库,编译时要加上链接参数-lm

6.超强实时性 获取纳秒级精度时间函数

intclock_gettime(clockid_t clk_id,structtimespec *tp);

函数功能:函数"clock_gettime"是基于Linux C语言的时间函数,他可以用于计算精度和纳秒

Get current value of CLOCK and store it in TP.

参数

clk_id : 检索和设置的clk_id指定的时钟时间。
struct timespec {
<span style="white-space:pre">	</span>time_t tv_sec; <span style="white-space:pre">	</span>/* 秒*/
<span style="white-space:pre">	</span>long tv_nsec; <span style="white-space:pre">	</span>/* 纳秒*/
};

例:提供一个ms秒数转换成timespec类型的纳秒级函数,可以应用到很多程序中,比如有超时设置的pthread mutex之类的啦。
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <time.h>	// clock_gettime
#include <errno.h>

#define NO_WAIT	0
#define WAIT_FOREVER (-1)

// ms -> timespec(sec and nsec)
static inline void getTimespec(int wait_ms, struct timespec *tp)
{
	time_t sec, t;
	long long nsec;

	sec = 0;
	if (wait_ms == NO_WAIT)
	{
		nsec = 0;
	}
	else
	{
		nsec = wait_ms * 1000000LL;
	}

	if (clock_gettime(CLOCK_REALTIME, tp) == -1)	//get now time
	{
		printf("getTimespec: clock_gettime call fail, error %d(%s)\n", errno, strerror(errno));
		tp->tv_sec = time(NULL) + 1;
		tp->tv_nsec = 0;
	}
	else
	{
		t = time(NULL) + 1;
		if ((int)(tp->tv_sec - t) > 30) 
		{
			tp->tv_sec = t;
			tp->tv_nsec = 0;
		}
	}

	nsec += tp->tv_nsec;
//	printf("getTimespec: current time sec = %ld, time = %ld, nsec = %ld, total nsec = %lld\n", tp->tv_sec, time(NULL)+1, tp->tv_nsec, nsec);
	if (nsec >= 1000000000)	// if nsec > 1sec
	{
		sec = nsec / 1000000000;
		nsec = nsec % 1000000000;
	}
	tp->tv_sec += sec;
	tp->tv_nsec = nsec;
//	printf("getTimespec: after time sec = %ld, time = %ld, nsec = %ld\n", tp->tv_sec, time(NULL)+1, tp->tv_nsec);

	return;
}


7.延时函数

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


五、小结

今天罗列了linux中常见的时间获取API和一些简单的相关例子,linux的时间编程(二) - 定时器 中将讲述linux中定时器的常用API和相关应用。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值