Linux内核中mktime()函数算法分析

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情
 

内核中的mktime()函数位于kernel/time.c内

该函数主要用于内核启动时,将CMOS中的 年-月-日 时:分:秒 信息转换为距离1970-01-01 00:00:00的秒数

 

具体定义如下:

 

unsigned long
mktime(const unsigned int year0, const unsigned int mon0,
       const unsigned int day, const unsigned int hour,
       const unsigned int min, const unsigned int sec)
{
	unsigned int mon = mon0, year = year0;

	/* 1..12 -> 11,12,1..10 */
	if (0 >= (int) (mon -= 2)) {
		mon += 12;	/* Puts Feb last since it has leap day */
		year -= 1;
	}

	return ((((unsigned long)
		  (year/4 - year/100 + year/400 + 367*mon/12 + day) +
		  year*365 - 719499
	    )*24 + hour /* now have hours */
	  )*60 + min /* now have minutes */
	)*60 + sec; /* finally seconds */
}

 

注意到计算的结果为相对时间

具体的计算方法也进行了两次相对运算

1、将时间轴整体后移2个月,以方便闰年的计算

原来相对1970-01-01 00:00:00,变成了相对1969-11-01 00:00:00

被计算的参数时间数值上也相对移位减小

但是这并不影响原来的相对差值

2、时间基准点为1-1-1 00:00:00(移位2个月后的)

即分别计算参数时间与基准点的秒数A

和1969-11-01 00:00:00与基准点的秒数B

然后A - B即最终结果

 

因为 天 时:分:秒 的相对基准固定

故算法中主要关心年份和月份到天数的转换

 

先考虑通用的 年-月-日 转天数的计算方法

例如:计算year-mon-day距离公元1-1-1的天数

公式可以表示为:(year - 1) * 365 + f(mon) + (day - 1) + leap_days

f(mon)表示关于mon的一个函数关系

mktime.c----Linux源码自读          最近刚看完了>,认真学习了下GCC里的内嵌汇编这部分,有学习了MAKEFILE的写法,现在及以后就要专心阅读LINUX的源码了.由于INTEL保护模式编程以前看过,LINUX的启动引导部分以前也看过了,就都不看了.只是大概有个理解.今天看了下mktime.c这个文件,比较简单的部分,也算给自己点信心吧.:-)        下面是我的理解及注释:00001 /*000 阅读详情

相关推荐

Linux内核完全注释》pdf v3.0

Linux内核完全注释》pdf v3.0

水土精灵的专栏 1万+

Linux源码中的mktime算法解析

Linux源码中的mktime算法解析 我们知道,从CMOS中读出来的系统时间并不是time_t类型,而是类似于struct tm那样,年月日时分秒是分开存储的。 那么,要把它转化为系统便于处理的time_t类型,就需要算法进行转换。 我们都知道我们的公历还是比较复杂的,有大月小月,有闰年非闰年,处理起来会很麻烦。 但是Linux的源代码仅仅用了短短的

axx1611的专栏 2万+

ACE_OS::mktime函数源代码

static __time64_t __cdecl _make__time64_t ( struct tm *tb, int ultflag ) { __time64_t tmptm1, tmptm2, tmptm3; struct tm tbtemp; long dstbias = 0; long timezone = 0; _VALIDATE_RETURN( ( tb != NULL ), EINVAL, ( ( __time64_t )( -1 ) ) ) /* * First, make sure tm_year is reasonably close to being in range. */ if ( ((tmptm1 = tb->tm_year) _MAX_YEAR64 + 1) ) goto err_mktime; /* * Adjust month value so it is in the range 0 - 11. This is because * we don't know how many days are in months 12, 13, 14, etc. */ if ( (tb->tm_mon tm_mon > 11) ) { tmptm1 += (tb->tm_mon / 12); if ( (tb->tm_mon %= 12) tm_mon += 12; tmptm1--; } /* * Make sure year count is still in range. */ if ( (tmptm1 _MAX_YEAR64 + 1) ) goto err_mktime; } /***** HERE: tmptm1 holds number of elapsed years *****/ /* * Calculate days elapsed minus one, in the given year, to the given * month. Check for leap year and adjust if necessary. */ tmptm2 = _days[tb->tm_mon]; if ( _IS_LEAP_YEAR(tmptm1) && (tb->tm_mon > 1) ) tmptm2++; /* * Calculate elapsed days since base date (midnight, 1/1/70, UTC) * * * 365 days for each elapsed year since 1970, plus one more day for * each elapsed leap year. no danger of overflow because of the range * check (above) on tmptm1. */ tmptm3 = (tmptm1 - _BASE_YEAR) * 365 + _ELAPSED_LEAP_YEARS(tmptm1); /* * elapsed days to current month (still no possible overflow) */ tmptm3 += tmptm2; /* * elapsed days to current date. */ tmptm1 = tmptm3 + (tmptm2 = (__time64_t)(tb->tm_mday)); /***** HERE: tmptm1 holds number of elapsed days *****/ /* * Calculate elapsed hours since base date */ tmptm2 = tmptm1 * 24; tmptm1 = tmptm2 + (tmptm3 = (__time64_t)tb->tm_hour); /***** HERE: tmptm1 holds number of elapsed hours *****/ /* * Calculate elapsed minutes since base date */ tmptm2 = tmptm1 * 60; tmptm1 = tmptm2 + (tmptm3 = (__time64_t)tb->tm_min); /***** HERE: tmptm1 holds number of elapsed minutes *****/ /* * Calculate elapsed seconds since base date */ tmptm2 = tmptm1 * 60; tmptm1 = tmptm2 + (tmptm3 = (__time64_t)tb->tm_sec); /***** HERE: tmptm1 holds number of elapsed seconds *****/ if ( ultflag ) { /* * Adjust for timezone. No need to check for overflow since * localtime() will check its arg value */ __tzset(); _ERRCHECK(_get_dstbias(&dstbias;)); _ERRCHECK(_get_timezone(&timezone;)); tmptm1 += timezone; /* * Convert this second count back into a time block structure. * If localtime returns NULL, return an error. */ if ( _localtime64_s(&tbtemp;, &tmptm1;) != 0 ) goto err_mktime; /* * Now must compensate for DST. The ANSI rules are to use the * passed-in tm_isdst flag if it is non-negative. Otherwise, * compute if DST applies. Recall that tbtemp has the time without * DST compensation, but has set tm_isdst correctly. */ if ( (tb->tm_isdst > 0) || ((tb->tm_isdst 0)) ) { tmptm1 += dstbias; if ( _localtime64_s(&tbtemp;, &tmptm1;) != 0 ) goto err_mktime; } } else { if ( _gmtime64_s(&tbtemp;, &tmptm1;) != 0) goto err_mktime; } /***** HERE: tmptm1 holds number of elapsed seconds, adjusted *****/ /***** for local time if requested *****/ *tb = tbtemp; return tmptm1; err_mktime: /* * All errors come to here */ errno = EINVAL; return (__time64_t)(-1); }

linuxmktime函数,关于kernel_mktime 函数详解

kernel_mktime函数详解这几天在linux内核QQ群中看到很多成员都在询问linux0.11版中kernel_mktime函数原理,看来大家都对linux内核很感兴趣啊!下面详细的讲解其原理以供大家参考。以下是kernel_mktime函数原码:/***这段代码理解起来因该没问题***/#define MINUTE 60#define HOUR (60*MINUTE)#define DA...

weixin_30039311的博客 806

Linux mktime 源代码简析

之前已经有人对这个源代码做过分析了,参见http://blog.csdn.net/axx1611/article/details/1792827?reload 这里选择从另外一个角度再次解析这部分代码,建议先阅读上面的博客内容: /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. * Assum

ok2222991的专栏 4456

时间转秒函数c语言,c语言函数mktime()如何将时间转换成经过的秒数实例源码

c语言函数mktime()如何将时间转换成经过的秒数实例源码。需要引入的头文件:#include 定义函数:time_t mktime(strcut tm * timeptr);函数mktime()使用介绍:mktime()用来将参数timeptr 所指的tm 结构数据转换成从公元1970 年1 月1 日0 时0 分0 秒算起至今的UTC 时间所经过的秒数。返回值:返回经过的秒数。mktime()...

weixin_26945061的博客 1686

Linux中的gmtime和localtime,mktime算法

#include time_t time(time_t *calptr) //time函数返回从1970年1月1日的UTC时间的0时0分0秒算起到现在所有的秒数 struct tm *gmtime(const time_t *calptr) //将其转换为标准时间 struct tm *localtime(const time_t *calptr) //将其转换为本地时间 以上两个

just do it 4401

linux mktime函数的实现,Linux内核mktime()函数算法分析

Linux内核中的mktime()函数位于kernel/time.c内该函数主要用于内核启动时,将CMOS中的 年-月-日 时:分:秒 信息转换为距离1970-01-01 00:00:00的秒数具体定义如下:unsignedlongmktime(constunsignedintyear0,constunsignedintmon0,constunsignedintday,constunsignedi...

weixin_39876595的博客 3911

linux 算法函数,Linux内核mktime()函数算法分析

Linux内核中的mktime()函数位于kernel/time.c内该函数主要用于内核启动时,将CMOS中的 年-月-日 时:分:秒 信息转换为距离1970-01-01 00:00:00的秒数具体定义如下:unsignedlongmktime(constunsignedintyear0,constunsignedintmon0,constunsignedintday,constunsignedi...

weixin_39601194的博客 321

linux 内核mktime函数

Linux内核中的mktime()函数位于kernel/time.c内 该函数主要用于内核启动时,将CMOS中的 年-月-日 时:分:秒 信息转换为距离1970-01-01 00:00:00的秒数 具体定义如下:   unsigned long  mktime(const unsigned int year0, const unsigned int mo

lgflgf的专栏 821

Linux内核源码分析--系统时间初始化(kernel_mktime()函数

从boot文件中的几个汇编程序执行后跳转到init文件中的main.c程序开始继续执行,该main.c函数式为系统运行的环境进行初始化的。首先来看系统时间的初始化(因为系统时间的初始化开始程序就在init文件中),其中主要还是由kernel中的mktime.c程序中的kernel_mktime函数计算时间的。         先看下time_init(void)函数及相关结构是怎么实现的:

YuZhiHui_No1的专栏 4061

kernel_mktime 函数详解

kernel_mktime函数详解   这几天在linux内核QQ群中看到很多成员都在询问linux0.11版中kernel_mktime函数原理,看来大家都对linux内核很感兴趣啊!下面详细的讲解其原理以供大家参考。   以下是kernel_mktime函数原码:   /***这段代码理解起来因该没问题***/ #define MINUTE 60 #define HOUR (6

linux专栏 1945

linux-mktime.c

/* *  linux/kernel/mktime.c *                                            //--内核专用的计算1970年以来经过的秒数时间 *  (C) 1991  Linus Torvalds */#include /* * This isnt the library routine, it is only

四菜一汤 3183

linux mktime

核中的mktime()函数位于kernel/time.c内 该函数主要用于内核启动时,将CMOS中的 年-月-日 时:分:秒 信息转换为距离1970-01-01 00:00:00的秒数   具体定义如下:   [cpp] view plaincopyprint? unsigned long   mktime(const unsi

902

Linux下用户态mktime实现参考

1、背景 项目中使用发现mktime开销较大,使用性能测试工具测试一下; 2、接口说明 主要用于所指向的结构转换为自 1970 年1月1日以来持续时间的秒数,发生错误时返回-1。 SYNOPSIS top #include <time.h> time_t mktime(struct tm *timeptr); DESCRIPTION The functionality described on this reference page i

staticnetwind的专栏 5248

Linux内核定时器函数mktime

Linux源码中的mktime算法解析     我们知道,从CMOS中读出来的系统时间并不是time_t类型,而是类似于struct tm那样,年月日时分秒是分开存储的。     那么,要把它转化为系统便于处理的time_t类型,就需要算法进行转换。     我们都知道我们的公历还是比较复杂的,有大月小月,有闰年非闰年,处理起来会很麻烦。     但是Linux的源代码仅仅用了短短的几行就

wjflyhigh的专栏 884

linux程序mktime无权限,linux-mktime.c

/**linux/kernel/mktime.c*//--内核专用的计算1970年以来经过的秒数时间*(C) 1991Linus Torvalds*/#include /** This isn't the library routine, it is only used in the kernel....

weixin_29616999的博客 133
上一篇: Linux内核加载过程
下一篇: 地址空间
kernel_digger
博客等级 码龄15年 18粉丝 19原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值