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这个变量记录的其实是段时间(其实就是当前时间和(UTC)这个时间的差值)
(3)一个时间节拍取决于OS的配置,现代linux系统一般是10ms或者1ms。这个时间其实就是调度时间,在内核中用HZ来记录和表示。如果HZ定义成1000那么时钟节拍就是1/HZ。
3.linux中时间相关的系统调用
(1)常用的时间相关的API和库函数: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 他们结构体表示的时间。区别是gmtime得到的是国际时间,localtime得到的是本地(OS系统时区设置的)时间。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中计算得来的),只不过不同的函数返回的格式不同,静读不同。
4.实战编程1
(1)time能得到一个当前时间距离标准起点时间(UTC)过去了多少秒。
#include <stdio.h>
#include <time.h>
int main(void)
{
time_t tNow = 0;
//time_t time(time_t *tloc);这里的参数没有const修饰说明做的是输出型参数
//tNow = time(NULL); //这是用返回值表示
time(&tNow); //这时用内部参数做输出表示(指针做输出型参数)
if(tNow < 0)
{
perror("time");
return -1;
}
printf("time:%ld\n",tNow);
return 0;
}
(2)ctime可以从time_t出发得到一个可以容易观察的字符串格式的时间,缺点是打印时间的格式是固定的。
#include <stdio.h>
#include <time.h>
int main(void)
{
time_t tNow = 0;
//time_t time(time_t *tloc);这里的参数没有const修饰说明做的是输出型参数
//tNow = time(NULL); //这是用返回值表示
time(&tNow); //这时用内部参数做输出表示(指针做输出型参数)
if(tNow < 0)
{
perror("time");
return -1;
}
printf("time:%ld\n",tNow);
//char *ctime(const time_t *timep);
printf("ctime: %s\n",ctime(&tNow));
return 0;
}
(3)gmtime和localtime
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
time_t tNow = 0;
struct tm *tmNow = NULL;
tmNow = (struct tm *)malloc(sizeof(struct tm));
//time_t time(time_t *tloc);这里的参数没有const修饰说明做的是输出型参数
//tNow = time(NULL); //这是用返回值表示
time(&tNow); //这时用内部参数做输出表示(指针做输出型参数)
if(tNow < 0)
{
perror("time");
return -1;
}
printf("time:%ld\n",tNow);
//char *ctime(const time_t *timep);
printf("ctime: %s\n",ctime(&tNow));
memset(tmNow,0,sizeof(tmNow));
//struct tm *gmtime_r(const time_t *timep, struct tm *result);
gmtime_r(&tNow,tmNow);
printf("%d年%d月%d日%d时%d分%d秒\n这一年的第%d天\n",
tmNow->tm_year,tmNow->tm_mon,tmNow->tm_mday,
tmNow->tm_hour,tmNow->tm_min,tmNow->tm_sec,tmNow->tm_yday);
//struct tm *localtime_r(const time_t *timep, struct tm *result);
localtime_r(&tNow,tmNow);
printf("%d年%d月%d日%d时%d分%d秒\n这一年的第%d天\n",
tmNow->tm_year,tmNow->tm_mon,tmNow->tm_mday,
tmNow->tm_hour,tmNow->tm_min,tmNow->tm_sec,tmNow->tm_yday);
return 0;
}
5.实战编程2
(1)mktime用来向操作系统设置时间用的
(2)asctime得到一个固定格式的字符串式的当前时间,效果上和ctime一样的,区别在于ctime从time_t出发,而asctime从struct_tm出发。
#include <time.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
time_t tNow = 0;
struct tm tmNow;
//time_t time(time_t *tloc);这里的参数没有const修饰说明做的是输出型参数
//tNow = time(NULL); //这是用返回值表示
time(&tNow); //这时用内部参数做输出表示(指针做输出型参数)
if(tNow < 0)
{
perror("time");
return -1;
}
printf("time:%ld\n",tNow);
//char *ctime(const time_t *timep);
printf("ctime: %s\n",ctime(&tNow));
memset(&tmNow,0,sizeof(tmNow));
//struct tm *gmtime_r(const time_t *timep, struct tm *result);
gmtime_r(&tNow,&tmNow);
printf("%d年%d月%d日%d时%d分%d秒\n这一年的第%d天\n",
tmNow.tm_year,tmNow.tm_mon,tmNow.tm_mday,
tmNow.tm_hour,tmNow.tm_min,tmNow.tm_sec,tmNow.tm_yday);
//struct tm *localtime_r(const time_t *timep, struct tm *result);
localtime_r(&tNow,&tmNow);
printf("%d年%d月%d日%d时%d分%d秒\n这一年的第%d天\n",
tmNow.tm_year,tmNow.tm_mon,tmNow.tm_mday,
tmNow.tm_hour,tmNow.tm_min,tmNow.tm_sec,tmNow.tm_yday);
//time_t mktime(struct tm *tm);
printf("mktime:%ld\n",mktime(&tmNow)); //必须经过localtime或gmtime装换成struct_tm才能准确打印
printf("asctime:%s\n",asctime(&tmNow)); //必须经过localtime或gmtime装换成struct_tm才能准确打印
return 0;
}
(3)strftime在asctime和ctime的基础上加了自定义格式
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
time_t tNow = 0;
struct tm tmNow;
char buf[100] = {0};
//time_t time(time_t *tloc);这里的参数没有const修饰说明做的是输出型参数
//tNow = time(NULL); //这是用返回值表示
time(&tNow); //这时用内部参数做输出表示(指针做输出型参数)
if(tNow < 0)
{
perror("time");
return -1;
}
printf("time:%ld\n",tNow);
//char *ctime(const time_t *timep);
printf("ctime: %s\n",ctime(&tNow));
memset(&tmNow,0,sizeof(tmNow));
//struct tm *gmtime_r(const time_t *timep, struct tm *result);
gmtime_r(&tNow,&tmNow);
printf("%d年%d月%d日%d时%d分%d秒\n这一年的第%d天\n",
tmNow.tm_year,tmNow.tm_mon,tmNow.tm_mday,
tmNow.tm_hour,tmNow.tm_min,tmNow.tm_sec,tmNow.tm_yday);
//struct tm *localtime_r(const time_t *timep, struct tm *result);
localtime_r(&tNow,&tmNow);
printf("%d年%d月%d日%d时%d分%d秒\n这一年的第%d天\n",
tmNow.tm_year,tmNow.tm_mon,tmNow.tm_mday,
tmNow.tm_hour,tmNow.tm_min,tmNow.tm_sec,tmNow.tm_yday);
//time_t mktime(struct tm *tm);
printf("mktime:%ld\n",mktime(&tmNow)); //必须经过localtime或gmtime装换成struct_tm才能准确打印
printf("asctime:%s\n",asctime(&tmNow)); //必须经过localtime或gmtime装换成struct_tm才能准确打印
memset(buf,0,sizeof(buf));
//size_t strftime(char *s, size_t max, const char *format,const struct tm *tm)
strftime(buf,sizeof(buf),"%Y-%m-%d,%H-%M-%S",&tmNow);
printf("时间为:[%s]\n",buf);
return 0;
}
(4)gettimeofday和settimeofday是和time函数那一系列以秒为单位来获取时间的不同的以微妙为单位获取时间。
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
int main(void)
{
time_t tNow = 0;
struct tm tmNow;
char buf[100] = {0};
int ret = -1;
struct timeval tv = {0};
struct timezone tz = {0};
//time_t time(time_t *tloc);这里的参数没有const修饰说明做的是输出型参数
//tNow = time(NULL); //这是用返回值表示
time(&tNow); //这时用内部参数做输出表示(指针做输出型参数)
if(tNow < 0)
{
perror("time");
return -1;
}
printf("time:%ld\n",tNow);
//char *ctime(const time_t *timep);
printf("ctime: %s\n",ctime(&tNow));
memset(&tmNow,0,sizeof(tmNow));
//struct tm *gmtime_r(const time_t *timep, struct tm *result);
gmtime_r(&tNow,&tmNow);
printf("%d年%d月%d日%d时%d分%d秒\n这一年的第%d天\n",
tmNow.tm_year,tmNow.tm_mon,tmNow.tm_mday,
tmNow.tm_hour,tmNow.tm_min,tmNow.tm_sec,tmNow.tm_yday);
//struct tm *localtime_r(const time_t *timep, struct tm *result);
localtime_r(&tNow,&tmNow);
printf("%d年%d月%d日%d时%d分%d秒\n这一年的第%d天\n",
tmNow.tm_year,tmNow.tm_mon,tmNow.tm_mday,
tmNow.tm_hour,tmNow.tm_min,tmNow.tm_sec,tmNow.tm_yday);
//struct tm *localtime_r(const time_t *timep, struct tm *result);
localtime_r(&tNow,&tmNow);
printf("%d年%d月%d日%d时%d分%d秒\n这一年的第%d天\n",
tmNow.tm_year,tmNow.tm_mon,tmNow.tm_mday,
tmNow.tm_hour,tmNow.tm_min,tmNow.tm_sec,tmNow.tm_yday);
//time_t mktime(struct tm *tm);
printf("mktime:%ld\n",mktime(&tmNow)); //必须经过localtime或gmtime装换成struct_tm才能准确打印
printf("asctime:%s\n",asctime(&tmNow)); //必须经过localtime或gmtime装换成struct_tm才能准确打印
memset(buf,0,sizeof(buf));
//size_t strftime(char *s, size_t max, const char *format,const struct tm *tm)
strftime(buf,sizeof(buf),"%Y-%m-%d,%H-%M-%S",&tmNow);
printf("时间为:[%s]\n",buf);
//int gettimeofday(struct timeval *tv, struct timezone *tz);
ret = gettimeofday(&tv,&tz);
if(ret < 0)
{
perror("gettimeofday");
return -1;
}
printf("second:%ld\n",tv.tv_sec);
printf("microsecond:%ld\n",tv.tv_usec);
printf("timezone:%d\n",tz.tz_minuteswest);
return 0;
}