From: John Hodge Date: Tue, 24 Jan 2012 06:59:28 +0000 (+0800) Subject: Kernel - Fixing time formatting functions (not fully tested) X-Git-Tag: rel0.15~792^2~18 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=689780bf5a2bbd14190c770eb3b84fe2b541181f;p=tpg%2Facess2.git Kernel - Fixing time formatting functions (not fully tested) --- diff --git a/Kernel/lib.c b/Kernel/lib.c index 76cc4286..a3ad7316 100644 --- a/Kernel/lib.c +++ b/Kernel/lib.c @@ -39,6 +39,9 @@ char **str_split(const char *__str, char __ch); int WriteUTF8(Uint8 *str, Uint32 Val); int DivUp(int num, int dem); Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year); +#endif +void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms); +#if 0 int rand(void); int CheckString(char *String); @@ -769,28 +772,116 @@ int WriteUTF8(Uint8 *str, Uint32 Val) * \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year) * \brief Converts a date into an Acess Timestamp */ -Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year) +Sint64 timestamp(int sec, int min, int hrs, int day, int month, int year) { + int is_leap; Sint64 stamp; - stamp = sec; - stamp += mins*60; - stamp += hrs*3600; - - stamp += day*3600*24; - stamp += month*DAYS_BEFORE[month]*3600*24; - if( ( - ((year&3) == 0 || year%100 != 0) - || (year%100 == 0 && ((year/100)&3) == 0) - ) && month > 1) // Leap year and after feb - stamp += 3600*24; + + if( !(0 <= sec && sec < 60) ) return 0; + if( !(0 <= min && min < 60) ) return 0; + if( !(0 <= hrs && hrs < 24) ) return 0; + if( !(0 <= day && day < 31) ) return 0; + if( !(0 <= month && month < 12) ) return 0; + + stamp = DAYS_BEFORE[month] + day; + + // Every 4 years + // - every 100 years + // + every 400 years + is_leap = (year % 4 == 0) - (year % 100 == 0) + (year % 400 == 0); + ASSERT(is_leap == 0 || is_leap == 1); + + if( is_leap && month > 1 ) // Leap year and after feb + stamp += 1; + + // Get seconds before the first of specified year + year -= 2000; // Base off Y2K + // base year days + total leap year days + stamp += year*365 + (year/400) - (year/100) + (year/4); - stamp += ((365*4+1) * ((year-2000)&~3)) * 3600*24; // Four Year Segments - stamp += ((year-2000)&3) * 365*3600*24; // Inside four year segment + stamp *= 3600*24; stamp += UNIX_TO_2K; + stamp += sec; + stamp += mins*60; + stamp += hrs*3600; return stamp * 1000; } +void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms) +{ + int is_leap = 0, i; + + inline Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R) + { + int sign = (N < 0) != (D < 0); + if(N < 0) N = -N; + if(D < 0) D = -D; + if(sign) + return -DivMod64U(N, D, (Uint64*)R); + else + return DivMod64U(N, D, (Uint64*)R); + } + + // Get within-day time + // TODO: Leap-seconds? + { + Sint64 rem; + TS = DivMod64( TS, 1000, &rem ); + *ms = rem; + TS = DivMod64( TS, 60, &rem ); + *sec = rem; + TS = DivMod64( TS, 60, &rem ); + *mins = rem; + TS = DivMod64( TS, 24, &rem ); + *hrs = rem; + } + + // Adjust to Y2K + TS -= UNIX_TO_2K/(3600*24); + + // Year (400 yr blocks) - (400/4-3) leap years + *year = 400 * DivMod64( TS, 365*400 + (400/4-3), &TS ); + if( TS < 366 ) // First year in 400 is a leap + is_leap = 1; + else + { + // 100 yr blocks - 100/4-1 leap years + *year += 100 * DivMod64( TS, 365*100 + (100/4-1), &TS ); + if( TS < 366 ) // First year in 100 isn't a leap + is_leap = 0; + else + { + *year += 4 * DivMod64( TS, 365*4 + 1, &TS ); + if( TS < 366 ) // First year in 4 is a leap + is_leap = 1; + else + { + *year += DivMod64( TS, 356, &TS ); + } + } + } + *year += 2000; + + ASSERT(TS >= 0); + + *day = 0; + // Month (if after the first of march, which is 29 Feb in a leap year) + if( is_leap && TS > DAYS_BEFORE[2] ) { + TS -= 1; // Shifts 29 Feb to 28 Feb + *day = 1; + } + // Get what month it is + for( i = 0; i < 12; i ++ ) { + if( TS < DAYS_BEFORE[i] ) + break; + } + *month = i - 1; + // Get day + TS -= DAYS_BEFORE[i-1]; + *day += TS; // Plus offset from leap handling above +} + /** * \fn int rand() * \brief Pseudo random number generator