⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 time.c

📁 一个类linux的dos下开发的操作系统.
💻 C
字号:
/*****************************************************************************
REALTIME CLOCK

EXPORTS:
unsigned long sys_time(void);
unsigned long year_month_date_to_time_t(unsigned short year,
		unsigned char month, unsigned char date);
*****************************************************************************/
#include <x86.h> /* inportb(), outportb() */
/*****************************************************************************
use BCD mode, since binary mode seems to be buggy
*****************************************************************************/
static unsigned char read_cmos(unsigned char reg)
{
	unsigned char high_digit, low_digit;

	outportb(0x70, reg);
	high_digit = low_digit = inportb(0x71);
/* convert from BCD to binary */
	high_digit >>= 4;
	high_digit &= 0x0F;
	low_digit &= 0x0F;
	return 10 * high_digit + low_digit;
}
/*****************************************************************************
Finds the number of days between two dates in the Gregorian calendar.
- it's a leap year if the year is divisible by 4,
- UNLESS the year is also divisible by 100,
- UNLESS the year is also divisible by 400

To compute Julian Day Number (JDN;
days since Nov 24, 4714 BC/BCE in Gregorian calendar):
	days_between_dates(-4713, 327, curr_day_in_year, curr_year);

To compute days since Jan 1, 1970 (UNIX epoch):
	days_between_dates(1970, 0, curr_day_in_year, curr_year);
or
    days_between_dates(-4713, 327, curr_day_in_year, curr_year) + 2440588L;

This code divides the time between start_day/start_year and end_day/end_year
into "slices": fourcent (400-year) slices in the middle, bracketed on
either end by century slices, fouryear (4-year) slices, and year slices.

When used to compute JDN, this code produces the same results as the
code shown here:
	http://serendipity.magnet.ch/hermetic/cal_stud/jdn.htm

IMHO, it's easier to see how the algorithm for this code works,
versus the code at the URL above.
*****************************************************************************/
static long days_between_dates(short start_year, unsigned short start_day,
		short end_year, unsigned short end_day)
{
	short fourcents, centuries, fouryears, years;
	long days;

	fourcents = end_year / 400 - start_year / 400;
	centuries = end_year / 100 - start_year / 100 -
/* subtract from 'centuries' the centuries already accounted for by
'fourcents' */
		fourcents * 4;
	fouryears = end_year / 4 - start_year / 4 -
/* subtract from 'fouryears' the fouryears already accounted for by
'fourcents' and 'centuries' */
		fourcents * 100 - centuries * 25;
	years = end_year - start_year -
/* subtract from 'years' the years already accounted for by
'fourcents', 'centuries', and 'fouryears' */
		400 * fourcents - 100 * centuries - 4 * fouryears;
/* add it up: 97 leap days every fourcent */
	days = (365L * 400 + 97) * fourcents;
/* 24 leap days every residual century */
	days += (365L * 100 + 24) * centuries;
/* 1 leap day every residual fouryear */
	days += (365L * 4 + 1) * fouryears;
/* 0 leap days for residual years */
	days += (365L * 1) * years;
/* residual days (need the cast!) */
	days += ((long)end_day - start_day);
/* account for terminal leap year */
	if(end_year % 4 == 0 && end_day >= 60)
	{
		days++;
		if(end_year % 100 == 0)
			days--;
		if(end_year % 400 == 0)
			days++;
	}
/* xxx - what have I wrought? I don't know what's going on here,
but the code won't work properly without it */
	if(end_year >= 0)
	{
		days++;
		if(end_year % 4 == 0)
			days--;
		if(end_year % 100 == 0)
			days++;
		if(end_year % 400 == 0)
			days--;
	}
	if(start_year > 0)
		days--;
	return days;
}
/*****************************************************************************
month and date start with 1, not with 0
*****************************************************************************/
#define	EPOCH_YEAR	1970
#define	EPOCH_DAY	0 /* Jan 1 */

unsigned long date_time_to_time_t(unsigned short year, unsigned char month,
		unsigned char date, unsigned char hour, unsigned char min,
		unsigned char sec)
{
	static const unsigned short days_to_date[12] =
	{
/*              jan  feb  mar  apr  may  jun  jul  aug  sep  oct  nov  dec */
		0,
		31,
		31 + 28,
		31 + 28 + 31,
		31 + 28 + 31 + 30,
		31 + 28 + 31 + 30 + 31,
		31 + 28 + 31 + 30 + 31 + 30,
		31 + 28 + 31 + 30 + 31 + 30 + 31,
		31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
		31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
		31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
		31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
	};
/**/
	unsigned long ret_val;
	unsigned short day;

/* convert month and year to day-in-year */
	if(month > 11 || date > 30)
		return 0;
	day = date + days_to_date[month];
/* convert to Unix JDN (UJDN) */
	ret_val = days_between_dates(EPOCH_YEAR, EPOCH_DAY, year, day);
/* convert from days to seconds, adding time as you go */
	ret_val *= 24;
	ret_val += hour;
	ret_val *= 60;
	ret_val += min;
	ret_val *= 60;
	ret_val += sec;
	return ret_val;
}
/*****************************************************************************
NOTE: this function works only with local time, stored in the CMOS clock.
It knows nothing of GMT or timezones. This is a feature, not a bug :)
*****************************************************************************/
unsigned long sys_time(void)
{
	static char init;
/**/
	unsigned short date, month, hour, minute, second;
	short year;

	if(!init)
	{
/* b2=0 BCD mode, vs. binary (binary mode seems to be buggy)
b1=1	24-hour mode, vs. 12-hour mode */
		outportb(0x70, 11);
		outportb(0x71, (inportb(0x71) & ~6) | 2);
		init = 1;
	}
/* wait for stored time value to stop changing */
	outportb(0x70, 10);
	while(inportb(0x71) & 128)
		/* nothing */;
/* get year/month/date
	year = read_cmos(9) + 1900;	xxx - OH NO, Y2K!
	year = read_cmos(9) + 2000;
use the Microsoft method -- this should be good from 1970-2069 */
	year = read_cmos(9);	/* 0-99 */
	if(year < 70)
		year += 2000;
	else
		year += 1900;
	month = read_cmos(8);	/* 1-12 */
	date = read_cmos(7);	/* 1-31 */
/* get time */
	hour = read_cmos(4);	/* 0-23 */
	minute = read_cmos(2);	/* 0-59 */
	second = read_cmos(0);	/* 0-59 */

	return date_time_to_time_t(year, month, date, hour, minute, second);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -