ZealOS/src/Kernel/KDate.CC
TomAwezome 7c6a2037d8 Reformatted some kernel files.
Changed DVD Resolution in DoDistro to 1024x768.
Kernel files reformatted: Display.CC, EdLite.CC, FunSeg.CC, Job.CC, KConfig.CC, KDataTypes.CC, KDate.CC, KDebug.CC, KDefine.CC, KExcept.CC, KExterns.CC, KGlobals.CC, KHashA.CC, KHashB.CC, KInterrupts.CC, KLoad.CC, KMain.CC, KStart16.CC, KStart32.CC.
2020-09-07 14:01:54 -04:00

240 lines
5.3 KiB
HolyC
Executable file

//See $LK,"::/Doc/TimeDate.DD"$
U16 month_start_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
U16 month_start_days_leap[12] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
I64 YearStartDate(I64 year)
{//32-bit day since AD 0, given year number.
I64 y1 = year - 1, yd4000 = y1 / 4000, yd400 = y1 / 400, yd100 = y1 / 100, yd4 = y1 / 4;
return year * 365 + yd4 - yd100 + yd400 - yd4000;
}
CDate Struct2Date(CDateStruct *_ds)
{//Convert CDateStruct to CDate.
CDate cdt;
I64 i1, i2;
i1 = YearStartDate(_ds->year);
i2 = YearStartDate(_ds->year + 1);
if (i2 - i1 == 365)
i1 += month_start_days[_ds->mon - 1];
else
i1 += month_start_days_leap[_ds->mon - 1];
cdt.date = i1 + _ds->day_of_mon - 1;
cdt.time = (_ds->sec10000 + 100 * (_ds->sec100 + 100 * (_ds->sec + 60 * (_ds->min + 60 * _ds->hour))))
<< 21 / (15 * 15 * 3 * 625);
return cdt;
}
I64 DayOfWeek(I64 i)
{//Day of week, given 32-bit day since AD 0.
i += CDATE_BASE_DAY_OF_WEEK;
if (i >= 0)
return i % 7;
else
return 6 - (6 - i) % 7;
}
U0 Date2Struct(CDateStruct *_ds, CDate cdt)
{//Convert CDate to CDateStruct.
I64 i, k, date = cdt.date;
_ds->day_of_week = DayOfWeek(date);
_ds->year = (date + 1) * 100000 / CDATE_YEAR_DAYS_INT;
i = YearStartDate(_ds->year);
while (i > date)
{
_ds->year--;
i = YearStartDate(_ds->year);
}
date -= i;
if (YearStartDate(_ds->year + 1) - i == 365)
{
k = 0;
while (date >= month_start_days[k + 1] && k < 11)
k++;
date -= month_start_days[k];
}
else
{
k = 0;
while (date >= month_start_days_leap[k + 1] && k < 11)
k++;
date -= month_start_days_leap[k];
}
_ds->mon = k + 1;
_ds->day_of_mon = date + 1;
k = (625 * 15 * 15 * 3 * cdt.time) >> 21 + 1;
_ds->sec10000 = ModU64(&k, 100);
_ds->sec100 = ModU64(&k, 100);
_ds->sec = ModU64(&k, 60);
_ds->min = ModU64(&k, 60);
_ds->hour = k;
}
I64 FirstDayOfMon(I64 i)
{//First day of month, given 32-bit day since AD 0.
CDateStruct ds;
CDate cdt = 0;
cdt.date = i;
Date2Struct(&ds, cdt);
ds.day_of_mon = 1;
cdt = Struct2Date(&ds);
return cdt.date;
}
I64 LastDayOfMon(I64 i)
{//Last day of month, given 32-bit day since AD 0.
CDateStruct ds;
CDate cdt = 0;
cdt.date = i;
Date2Struct(&ds, cdt);
ds.mon++;
if (ds.mon == 13)
{
ds.mon = 0;
ds.year++;
}
ds.day_of_mon = 1;
cdt = Struct2Date(&ds);
return cdt.date - 1;
}
I64 FirstDayOfYear(I64 i)
{//First day of year, given 32-bit day since AD 0.
CDateStruct ds;
CDate cdt = 0;
cdt.date = i;
Date2Struct(&ds, cdt);
ds.day_of_mon = 1;
ds.mon = 1;
cdt = Struct2Date(&ds);
return cdt.date;
}
I64 LastDayOfYear(I64 i)
{//Last day of year, given 32-bit day since AD 0.
CDateStruct ds;
CDate cdt = 0;
cdt.date = i;
Date2Struct(&ds, cdt);
ds.day_of_mon = 1;
ds.mon = 1;
ds.year++;
cdt = Struct2Date(&ds);
return cdt.date - 1;
}
U8 CMOSRegRead(I64 register)
{//Read val from CMOS register. See $LK,"CMOS Registers",A="MN:CMOSR_SEC"$.
OutU8(CMOS_SEL, register);
return InU8(CMOS_DATA);
}
U0 CMOSRegWrite(I64 register, I64 val)
{//Write val to CMOS register. See $LK,"CMOS Registers",A="MN:CMOSR_SEC"$.
OutU8(CMOS_SEL, register);
OutU8(CMOS_DATA, val);
}
Bool CMOSIsBcd()
{//Check of CMOS is in binary-coded decimal mode.
// Ex: 15:32:44 == 0x15:0x32:0x44 (not good). We use $LK,"Bcd2Binary",A="MN:Bcd2Binary"$() to convert.
return !(CMOSRegRead(CMOSR_STATUS_B) & CMOSF_BINARY);
}
I64 Bcd2Binary(U64 b)
{
I64 i, res = 0;
for (i = 0; i < 16; i++)
{
res = res * 10 + b >> 60;
b <<= 4;
}
return res;
}
U0 NowDateTimeStruct(CDateStruct *_ds)
{
I64 i;
U8 *b = _ds;
MemSet(_ds, 0, sizeof(CDateStruct));
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_SYS_DATE], 0))
PAUSE
do
{
while (CMOSRegRead(CMOSR_STATUS_A) & CMOSF_UPDATING)
PAUSE
b[2] = CMOSRegRead(CMOSR_SEC);
b[3] = CMOSRegRead(CMOSR_MIN);
b[4] = CMOSRegRead(CMOSR_HOUR);
b[5] = CMOSRegRead(CMOSR_DAY_OF_WEEK);
b[6] = CMOSRegRead(CMOSR_DAY_OF_MONTH);
b[7] = CMOSRegRead(CMOSR_MONTH);
b[8] = CMOSRegRead(CMOSR_YEAR);
}
while (CMOSRegRead(CMOSR_STATUS_A) & CMOSF_UPDATING);
LBtr(&sys_semas[SEMA_SYS_DATE], 0);
POPFD
if (CMOSIsBcd)
for (i = 2; i < 9; i++)
b[i] = Bcd2Binary(b[i]);
if (_ds->year > 255) _ds->year = 255;
_ds->year += 2000;
if (_ds->mon > 12) _ds->mon = 12;
if (_ds->day_of_mon > 31) _ds->day_of_mon = 31;
if (_ds->day_of_week > 6) _ds->day_of_week = 6;
if (_ds->hour > 23) _ds->hour = 23;
if (_ds->min > 59) _ds->min = 59;
if (_ds->sec > 59) _ds->sec = 59;
}
CDate Now()
{//Current datetime.
CDateStruct ds;
NowDateTimeStruct(&ds);
return Struct2Date(&ds)-local_time_offset;
}
U0 TimeSet(CDateStruct *ds)
{//Set CMOS time from user crafted $LK,"CDateStruct",A="MN:CDateStruct"$.
//$BK,1$Make sure to use hex as decimals if BCD mode.$BK,0$ Check using $LK,"CMOSIsBcd",A="MN:CMOSIsBcd"$().
//Ex: if bcd mode and we want 12/30, 10:45:15 -- 0x12/0x30, 0x10:0x45:0x15.
//Pass year as double digit number (obviously 20XX is too big for a U8).
U8 *b = ds;
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_SYS_DATE], 0))
PAUSE
while (CMOSRegRead(CMOSR_STATUS_A) & CMOSF_UPDATING)
PAUSE
CMOSRegWrite(CMOSR_SEC, b[2]);
CMOSRegWrite(CMOSR_MIN, b[3]);
CMOSRegWrite(CMOSR_HOUR, b[4]);
CMOSRegWrite(CMOSR_DAY_OF_WEEK, b[5]);
CMOSRegWrite(CMOSR_DAY_OF_MONTH, b[6]);
CMOSRegWrite(CMOSR_MONTH, b[7]);
CMOSRegWrite(CMOSR_YEAR, b[8]);
LBtr(&sys_semas[SEMA_SYS_DATE], 0);
POPFD
}