linux应用编程笔记(4)时间的概念/linux中的时间函数

(一)关于时间的概念

UTC和GMT时间

  1. 每个地区都有自己的本地时间,在网上以及无线电通信中时间转换的问题就显得格外突出。
  2. 整个地球分为二十四时区,每个时区都有自己的本地时间。在国际无线电通信场合,为了统一起见,使用一个统一的时间,称为通用协调时(UTC, Universal Time Coordinated)。UTC与格林尼治平均时(GMT, Greenwich Mean Time)一样,都与英国伦敦的本地时相同。在本文中,UTC与GMT含义完全相同。

linux系统中的时间

1.jiffies的引入

  1. jiffies是linux内核中的一个全局变量,这个变量用来记录以内核的节拍时间为单位时间长度的一个数值。
  2. 内核配置的时候定义了一个节拍时间,实际上linux内核的调度系统工作时就是以这个节拍时间为时间片的。
  3. jiffies变量开机时有一个基准值,然后内核每过一个节拍时间jiffies就会加1,然后到了系统的任意一个时间我们当前时间就被jiffies这个变量所标注。

2.linux系统如何记录时间

  1. 内核在开机启动的时候会读取RTC硬件获取一个时间作为初始基准时间,这个基准时间对应一个jiffies值(这个基准时间换算成jiffies值的方法是:用这个时间减去1970-01-01 00:00:00 +0000(UTC),然后把这个时间段换算成jiffies数值),这个jiffies值作为我们开机时的基准jiffies值存在。然后系统运行时每个时钟节拍的末尾都会给jiffies这个全局变量加1,因此操作系统就使用jiffies这个全局变量记录了下来当前的时间。当我们需要当前时间点时,就用jiffies这个时间点去计算(计算方法就是先把这个jiffies值对应的时间段算出来,然后加上1970-01-01 00:00:00 +0000(UTC)即可得到这个时间点)。
  2. 其实操作系统只在开机时读一次RTC,整个系统运行过程中RTC是无作用的。RTC的真正作用其实是在OS的2次开机之间进行时间的保存。
  3. 理解时一定要点时间和段时间结合起来理解。jiffies这个变量记录的其实是段时间(其实就是当前时间和1970-01-01 00:00:00 +0000(UTC)这个时间的差值)。
  4. 一个时间节拍的时间取决于操作系统的配置,现代linux系统一般是10ms或者1ms。这个时间其实就是调度时间,在内核中用HZ来记录和表示。如果HZ定义成1000难么时钟节拍就是1/HZ,也就是1ms。这些在学习驱动时会用到。

3.linux中时间相关的系统调用

  1. 常用的时间相关的API和C库函数有9个:time/ctime/localtime/gmtime/mktime/asctime/strftime/gettimeofday/settimeofday
  2. time系统调用返回当前时间以秒为单位的距离1970-01-01 00:00:00 +0000(UTC)过去的秒数。这个time内部就是用jiffies换算得到的秒数。其他函数基本都是围绕着time来工作的。
  3. gmtime和localtime会把time得到的秒数变成一个struct tm结构体表示的时间。区别是gmtime得到的是国际时间,而localtime得到的是本地(指的是你运行localtime函数的程序所在的计算机所设置的时区对应的本地时间)时间。mktime用来完成相反方向的转换(struct tm到time_t)
  4. 如果从struct tm出发想得到字符串格式的时间,可以用asctime或者strftime都可以。(如果从time_t出发想得到字符串格式的时间用ctime即可)
  5. gettimeofday返回的时间是由struct timeval和struct timezone这两个结构体来共同表示的,其中timeval表示时间,而timezone表示时区。settimeofday是用来设置当前的时间和时区的。
  6. 总结:不管用哪个系统调用,最终得到的时间本质上都是一个时间(这个时间最终都是从kernel中记录的jiffies中计算得来的),只不过不同的函数返回的时间的格式不同,精度不同。

(二)linux中的时间函数

time

#include <time.h>
time_t time(time_t *tloc);
  1. time能得到一个当前时间距离标准起点时间1970-01-01 00:00:00 +0000(UTC)过去了多少秒。

ctime

#include <time.h>
char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf);
  1. ctime可以从time_t出发得到一个容易观察的字符串格式的当前时间。
  2. ctime好处是很简单好用,可以直接得到当前时间的字符串格式,直接打印来看。坏处是ctime的打印时间格式是固定的,没法按照我们的想法去变。
  3. 实验结果可以看出ctime函数得到的时间是考虑了计算机中的本地时间的(计算机中的时区设置)。

gmtime/localtime

#include <time.h>
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);
  1. gmtime获取的时间中:年份是以1970为基准的差值,月份是0表示1月,小时数是以UTC时间的0时区为标准的小时数(北京是东8区,因此北京时间比这个时间大8)。
  2. localtime和gmtime的唯一区别就是localtime以当前计算机中设置的时区为小时的时间基准,其余一样。

mktime

#include <time.h>
time_t mktime(struct tm *tm);
  1. 从OS中读取时间时用不到mktime的。
  2. mktime( )将参数tm指向的tm结构体数据转换成从1970年1月1日00时00分00秒至今的GMT时间经过的秒数。

asctime

#include <time.h>
char *asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf);
  1. asctime得到一个固定格式的字符串格式的当前时间,效果上和ctime一样的。 区别是ctime从time_t出发,而asctime从struct tm出发。

strftime

#include <time.h>
size_t strftime(char *s, size_t max, const char *format,const struct tm *tm);
  1. asctime和ctime得到的时间字符串都是固定格式的,没法用户自定义格式。
  2. 如果需要用户自定义时间的格式,则需要用strftime。

gettimeofday/settimeofday

#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
int settimeofday(const struct timeval *tv, const struct timezone *tz);
  1. 前面讲到的基于time函数的那个系列都是以秒为单位来获取时间的,没有比秒更精确的时间。
  2. 有时候我们程序希望得到非常精确的时间(譬如以us为单位),这时候就只能通过gettimeofday来实现了。
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>

int main (int argc, char *argv[])
{
	time_t t_Now = 0;
	char Tmbuf[100];
	struct tm *pGmtime = NULL;
	struct tm Gmtime = {0};
	struct tm *pLocaltime = NULL;
	struct tm Localtime = {0};
	time_t mktm = 0;
	char buf[100];
	struct timeval tv = {0}; 
	struct timezone tz = {0};

/******time*********************************************/
	t_Now = time((time_t *)NULL);
	//输出结果单位是秒
	printf("time : [%ld]\n", t_Now);

/******ctime********************************************/
	memset(&Tmbuf, 0, sizeof(Tmbuf));
	ctime_r(&t_Now, Tmbuf);
	printf("ctime_r : %s", Tmbuf);

/******gmtime******************************************/
	pGmtime = gmtime(&t_Now);
	printf("gmtime : Year = [%d]  Mon = [%d]  Mday = [%d] hour = [%d]  min = [%d]\n", pGmtime->tm_year, pGmtime->tm_mon, pGmtime->tm_mday, pGmtime->tm_hour, pGmtime->tm_min);
	
/******localtime***************************************/
	localtime_r(&t_Now, &Localtime); 
	printf("localtime_r : Year = [%d]  Mon = [%d]  Mday = [%d] hour = [%d]  min = [%d]\n", Localtime.tm_year, Localtime.tm_mon, Localtime.tm_mday, Localtime.tm_hour, Localtime.tm_min);

/******mktime******************************************/	
	mktm = mktime(&Localtime);
	printf("mktime : [%ld]\n", mktm);

/******mktime******************************************/	
	printf("asctime : %s",asctime(&Localtime));

	memset(buf, 0, sizeof(buf));
	strftime(buf, sizeof(buf), "%Y * %m * %d, %H-%M-%S.", &Localtime);
	printf("strftime : [%s].\n", buf);

/******gettimeofday************************************/	
	if(gettimeofday(&tv, &tz) < 0)
	{
		perror("gettimeofday");
		_exit(-1);
	}
	else
	{
		printf("gettimeofday : [%ld]  [%ld] [%d] [%d] \n", tv.tv_sec, tv.tv_usec, tz.tz_minuteswest, tz.tz_dsttime);
	}

	return 0;
}

在这里插入图片描述

运行结果
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值