ZealOS/src/Kernel/KDate.CC

227 lines
5.2 KiB
HolyC
Raw Normal View History

2020-02-15 20:01:48 +00:00
//See $LK,"::/Doc/TimeDate.DD"$
U16 mon_start_days1[12]={
0,31,59,90,120,151,181,212,243,273,304,334};
U16 mon_start_days2[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)
2020-02-16 06:07:34 +00:00
{//Convert CDateStruct to CDate.
2020-02-15 20:01:48 +00:00
CDate cdt;
I64 i1,i2;
i1=YearStartDate(_ds->year);
i2=YearStartDate(_ds->year+1);
if (i2-i1==365)
i1+=mon_start_days1[_ds->mon-1];
else
i1+=mon_start_days2[_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)
2020-02-16 06:07:34 +00:00
{//Convert CDate to CDateStruct.
2020-02-15 20:01:48 +00:00
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>=mon_start_days1[k+1] && k<11)
k++;
date-=mon_start_days1[k];
} else {
k=0;
while (date>=mon_start_days2[k+1] && k<11)
k++;
date-=mon_start_days2[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)
2020-02-15 20:01:48 +00:00
{
I64 i,res = 0;
for (i = 0; i < 16; i++)
{
res = res * 10 + b >> 60;
b <<= 4;
2020-02-15 20:01:48 +00:00
}
return res;
}
U0 NowDateTimeStruct(CDateStruct *_ds)
{
I64 i;
U8 *b = _ds;
2020-02-15 20:01:48 +00:00
MemSet(_ds, 0, sizeof(CDateStruct));
2020-02-15 20:01:48 +00:00
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_SYS_DATE],0))
PAUSE
do {
while (CMOSRegRead(CMOSR_STATUS_A) & CMOSF_UPDATING)
2020-02-15 20:01:48 +00:00
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);
2020-02-15 20:01:48 +00:00
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;
2020-02-15 20:01:48 +00:00
}
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
}