// datetime.c #include "common.h" #include "cstring.h" #include "cyber.h" #include "disk.h" #include "floating.h" #include "calend.h" #include "datetime.h" // Time stored as a SInt64 is in Mac system format, which is the number of // seconds since 12:00 a.m., Jan 1, 1904. static const SInt64 JDofDatum = 2451911; // Julian Date at noon on Mac OS datum, which is 2001 Jan 1 typedef struct { SInt64 jd; // Julian Date number + 0.5, i.e. JD at noon; 0 == 4713 B.C. Jan 1 (J) ushort hours, // 0 to 23 mins, // 0 to 59 secs; // 0 to 59 } datetime; // Conversion betweeen JD/time and SInt64 format static void datetoseconds(datetime *D, SInt64 *U) { if (!D || !U) return; *U= (D->jd - JDofDatum) * (SInt64)86400L; *U+= (3600L * D->hours) + (60L * D->mins) + D->secs; } static void secondstodate(SInt64 U, datetime *D) { if (!D) return; D->secs=mod(U,60); U= (U - D->secs) / 60; D->mins=mod(U,60); U= (U - D->mins) / 60; D->hours=mod(U,24); U= (U - D->hours) / 24; D->jd= U + JDofDatum; } // Date and time functions static char Calends[]={ 0,3,2,5,0,3,5,1,4,6,2,4 }; int gregdayofweek(int AD, int MONTH, int DATE) { if (MONTH<2) AD--; // This algorithm was not written by me return (AD + (AD/4) - (AD/100) + (AD/400) + Calends[MONTH] + DATE) % 7; } SInt64 secssincedatum(int YEAR, int MONTH, int DATE, int HOUR) { Date D; datetime DT; SInt64 T1; D.calend=GregorianCalendar; D.year=YEAR; D.month=MONTH; D.date=DATE; gregtojd(&D); DT.jd=D.jd; DT.hours=HOUR; DT.mins=0; DT.secs=0; datetoseconds(&DT,&T1); return T1; } SInt64 currentgmt(void) { //ulong U; MachineLocation ML; long L; //ReadLocation(&ML); L= (ML.u.gmtDelta << 8) >> 8; return CFAbsoluteTimeGetCurrent(); } static void rounddatetime(SInt64 *TIME, char UNIT) { datetime DT; int DOW; if (!TIME) return; switch (UNIT) { case 'w': secondstodate(*TIME,&DT); DOW=dayofweek(DT.jd); (*TIME)-= DOW * 86400L; return; case 'd': (*TIME)-=mod(*TIME,86400L); return; case 'h': (*TIME)-=mod(*TIME,3600); return; case 'm': (*TIME)-=mod(*TIME,60); return; } } void incrementtime(SInt64 *TIME, char UNIT, long NUM, bool Round) { Date D; datetime DT; if (!TIME) return; switch (UNIT) { case 'w': NUM*=7; // breaks case 'd': NUM*=24; // intentionally case 'h': NUM*=60; // omitted case 'm': NUM*=60; case 's': (*TIME)+=NUM; if (Round) rounddatetime(TIME,UNIT); return; case 'M': case 'y': secondstodate(*TIME,&DT); D.jd=DT.jd; D.calend=GregorianCalendar; jdtogreg(&D); if (UNIT=='y') D.year+=NUM; else { D.month+=NUM; D.year+= D.month / 12; D.month%=12; if (D.month<0) { D.month+=12; D.year--; } } if (Round) { D.date=0; DT.hours=0; DT.mins=0; DT.secs=0; if (UNIT=='y') D.month=0; } gregtojd(&D); DT.jd=D.jd; datetoseconds(&DT,TIME); return; } } // Date and time strings string timestring(SInt64 TIME) { datetime DT; char *S; secondstodate(TIME,&DT); S=cat3(5,fig(DT.hours),DT.mins<10 ? ":0" : ":",fig(DT.mins)); return cat3(5,S,DT.secs<10 ? ":0" : ":",fig(DT.secs)); } string datestring(SInt64 TIME, bool WeekDay) { datetime DT; Date D; char *S; secondstodate(TIME,&DT); D.jd=DT.jd; D.calend=GregorianCalendar; jdtogreg(&D); S=cat5(17,fig(D.year)," ",monthname(D.month)," ",fig(D.date + 1)); if (WeekDay) S=cat3(1,S,", ",dayname(dayofweek(DT.jd))); return S; } // Parsing date strings bool parseepoch(const char *S, SInt64 *TIME) { long Q; datetime DT; Date D; if (!S || !TIME) return 0; while (*S==' ') S++; if (!parseinteger(S,&Q)) return 0; while (numeral(*S)) S++; if (*(S++)!='.') return 0; if (*(S++)!='0') return 0; if (numeral(*S)) return 0; if (Q<1905 || Q>2040) return 0; D.year= Q - 1; D.month=11; D.date=30; // ? Confirm 12 a.m. on Dec 31, i.e. 24 h before New Year D.calend=GregorianCalendar; gregtojd(&D); DT.jd=D.jd; DT.hours=0; DT.mins=0; DT.secs=0; datetoseconds(&DT,TIME); return 1; } bool parsejuliandate(const char *S, SInt64 *TIME) { long Q; if (!S || !TIME) return 0; while (*S==' ') S++; if (!parseinteger(S,&Q)) return 0; while (numeral(*S)) S++; if (*(S++)!='.') return 0; if (*(S++)!='5') return 0; if (numeral(*S)) return 0; Q-= JDofDatum - 1; //if (Q<0) return 0; *TIME= Q * (SInt64)86400L; return 1; } bool parsenoraddate(const char *S, SInt64 *TIME) { real Q; char C; Date D; datetime DT; int DAYS; if (!S || !TIME) return 0; while (*S==' ') S++; D.year=1900; if (!numeral(C=S[0])) return 0; D.year+= 10 * (C - '0'); if (!numeral(C=S[1])) return 0; D.year+= C - '0'; if (D.year<=1940) D.year+=100; S+=2; D.month=0; D.date=0; D.calend=GregorianCalendar; gregtojd(&D); DT.jd=D.jd; if (!parsereal(S,&Q)) return 0; DAYS=(int)Q; Q-=DAYS; DT.jd+=DAYS; Q*=24.0; DT.hours=(int)Q; Q-=DT.hours; Q*=60.0; DT.mins=(int)Q; Q-=DT.mins; Q*=60.0; DT.secs=(int)Q; datetoseconds(&DT,TIME); return 1; }