[313页]
8-5 mktime.c 程序
8-5-1 功能描述
该程序只有一个函数kernel_mktime(),仅供内核使用。计算从1970年1月1日0时起到开机当日经过的秒数(日历时间),作为开机时间。该函数与标准C库中提供的mktime()函数的功能完全一样,都是将tm结构表示的时间转换为UNIX日历时间。但是由于内核不是普通程序,不能调用开发环境库中的函数,因此这里就必须自己专门编写一个了。
8-5-2 代码注释
/*
* linux/kernel/mktime.c
*
* (C) 1991 Linus Torvalds
*/
#include <time.h>//时间头文件,定义了标准时间数据结构tm和一些处理时间函数原型。
/*
这不是库函数,它仅供内核使用。因此我们不关心小于1970年的年份等,但假定一起均很正常。同样,时间区域TZ问题也先忽略。我们只是尽可能简单地处理问题。最好能找到一些公开的库函数(尽管我认为minix的时间函数时公开的)。
另外,我恨那个设置1970年开始的人 - 难道他们就不能选择从一个闰年开始?
我恨格里高利历、罗马教皇、主教,我什么都不在乎。我是个脾气暴躁的人。
*/
#define MINUTE 60 //1分钟的秒数
#define HOUR (60*MINUTE) //1小时的秒数
#define DAY (24*HOUR) //1天的秒数
#define YEAR (365*DAY) //1年的秒数
/* 有趣的是我们考虑进了闰年 */
//下面以年为界限,定义了每个月开始时的秒数时间。
static int month[12] = {
0,
DAY*(31),
DAY*(31+29),
DAY*(31+29+31),
DAY*(31+29+31+30),
DAY*(31+29+31+30+31),
DAY*(31+29+31+30+31+30),
DAY*(31+29+31+30+31+30+31),
DAY*(31+29+31+30+31+30+31+31),
DAY*(31+29+31+30+31+30+31+31+30),
DAY*(31+29+31+30+31+30+31+31+30+31),
DAY*(31+29+31+30+31+30+31+31+30+31+30)
};
//该函数计算从1970年1月1日0时起到开机当日经过的秒数,作为开机时间。
//参数tm中各字段已经在init/main.c中被赋值,信息取自CMOS。
long kernel_mktime(struct tm * tm)
{
long res;
int year;
//首先计算1970年到现在经过的年数。因为是2位表示方式,所以会有2000年问题。
//解决办法:if(tm->tm_year<70)ti->tm_year += 100;
//由于UNIX计年份是从1970年算起。到1972年就是一个闰年,因此过3年(70,71,72)就是
//第1个闰年,从1970年开始的闰年数计算方式=1+(y-3)/4=(y+1)/4。
//因为我们的month数组的二月是有29天的,如果当年不是闰年且大于1月份,减去一天的秒数时间。
year = tm->tm_year - 70;
/* 为了获得正确的闰年数,这里需要这样一个魔幻值(y+1)*/
res = YEAR*year + DAY*((year+1)/4);
res += month[tm->tm_mon];
/* 以及(y+2)。如果(y+2)不是闰年,那么我们就必须进行调整(减去一天的秒数时间)。 */
if (tm->tm_mon>1 && ((year+2)%4))
res -= DAY;
res += DAY*(tm->tm_mday-1);
res += HOUR*tm->tm_hour;
res += MINUTE*tm->tm_min;
res += tm->tm_sec;
return res;
}
8-5-3 闰年的计算方法
闰年的基本计算方法是:
如果y能被4整除且不能被100整除,或者能被400整除,则y是闰年。