/* * Small. fast versions of gmtime() and mktime() that only handle UTC * (no timezone stuff, no daylight saving time). * * Reference: * Algorithm 199 from "Collected Algorithms from ACM" Volume 1 * Published by the Association for Computing Machinery, 1980. */ /* * This routine converts time as follows. * The epoch is 0000 Jan 1 1970 GMT. * The argument is a pointer to a structure containing * * tm_sec seconds (0-59) * tm_min minutes (0-59) * tm_hour hours (0-23) * tm_mday day of month (1-31) * tm_mon month (0-11) * tm_year year - 1900 (70- ) * * tm_isdst should be 0 or negative but is ignored. * * mktime(p) returns the number of seconds elapsed since the epoch. */ #include /* for time_t and struct tm */ /* If TEST is defined this file becomes s complete program that * tests the gmtime() and mktime() here against the ones in the C library. */ /* #define TEST */ #define HANDLE_NEGATIVE_TIMES #ifdef TEST /* Rename the versions in this file */ #define mktime kmtime #define gmtime mgtime #endif time_t mktime(struct tm *tm) { int d = tm->tm_mday, m = tm->tm_mon, ya = tm->tm_year; int k; /* Days since 28th February 1900 */ if (m > 1) m -= 2; else ya--, m += 10; k = (1461*ya)/4 + (153*m+2)/5 + d; /* 25509 is number of days from 28 Feb 1900 to 1 Jan 1970 */ return (k-25509)*(24*60*60) + tm->tm_hour*(60*60) + tm->tm_min*60 + tm->tm_sec; } /* * This routine converts time as follows. * The epoch is 0000 Jan 1 1970 GMT. * The argument time is in seconds since then. * mgtime(t) returns a pointer to an structure containing * * tm_sec seconds (0-59) * tm_min minutes (0-59) * tm_hour hours (0-23) * tm_mday day of month (1-31) * tm_mon month (0-11) * tm_year year - 1900 (70- ) * tm_wday weekday (0-6, Sun is 0) * tm_yday day of the year (0-364/5) * tm_isdst is daylight saving time in force? (always 0 = GMT) * * The routine does not work in Saudi Arabia which runs on Solar time. */ struct tm * gmtime(const time_t *tim) { register int d; /* workhorse variable */ register int y = 0,m,a; static struct tm tm; /* * This routine is good until year 2100 */ tm.tm_sec = (d = *tim % 86400)%60; tm.tm_min = (d/=60) % 60; tm.tm_hour = d/60; d = *tim / 86400; /* no of days */ #ifdef HANDLE_NEGATIVE_TIMES /* Handle negative times */ if (tm.tm_sec < 0) tm.tm_sec += 60, tm.tm_min--; if (tm.tm_min < 0) tm.tm_min += 60, tm.tm_hour--; if (tm.tm_hour < 0) tm.tm_hour += 24, d--; #endif /* * d is the day number. Generate day of the week. * The addend is 4 mod 7 (1/1/1970 was Thursday) */ tm.tm_wday = (d+4)%7; #ifdef HANDLE_NEGATIVE_TIMES /* Handle negative times */ if (tm.tm_wday < 0) tm.tm_wday += 7; #endif /* When munging this, bear in mind that for calculation * the year starts on March the 1st (yday == 0) */ /* deal with years 2000-2099 */ if ( d > 11016 /* 29 Feb 2000 */ ) { y = 100; } else y=0; y += ( d = ( 4 * ( d + 693902+25567 ) - 1 ) % 146097 | 3 ) / 1461; a = ( d = ( d % 1461 ) / 4 + 1 ) - 307; m = ( ( d *= 5 ) - 3 ) / 153; tm.tm_mday = ( d + 2 - 153 * m ) / 5; /* adjust for fact that day==0 is 1st Mar 0000 */ if ((m += 2) > 11) { m -= 12; y++; } tm.tm_yday = ( a >= 0 ? a : a+365 ); if ( (y & 3) == 0 && a < 0) tm.tm_yday++; tm.tm_mon=m; tm.tm_year=y; tm.tm_isdst = 0; return(&tm); } #include #include #include #ifdef TEST #undef gmtime #undef mktime main() { time_t t; /* Loop variable to test all days */ if (getenv("TZ") == NULL || *getenv("TZ") != '\0') { printf("Please export TZ=\n"); exit(1); } /* Loop through positive and negative values, testing * every day. We increment by slightly less than one day so that * different time of day is also tested. There are 49709 days to * test, so we slip by 2 seconds each iteration, thus cover every even * second in a 24-hour period. */ for (t = 0; t >= 0 || t <= -86400; t += (60*60*24)-2) { /* Test our gmtime() */ struct tm *this, *that; time_t his, hat; this = mgtime(&t); that = gmtime(&t); if (this->tm_year != that->tm_year || this->tm_mon != that->tm_mon || this->tm_mday != that->tm_mday) { printf("mgtime fails date at %ld: ", t); printf("this = %d-%d-%d, ", this->tm_year+1900, this->tm_mon+1, this->tm_mday); printf("that = %d-%d-%d\n", that->tm_year, that->tm_mon+1, that->tm_mday); } if (this->tm_hour != that->tm_hour || this->tm_min != that->tm_min || this->tm_sec != that->tm_sec) { printf("mgtime fails time at %ld: ", t); printf("this = %d:%d:%d, ", this->tm_hour, this->tm_min, this->tm_sec); printf("that = %d:%d:%d\n", that->tm_hour, that->tm_min, that->tm_sec); } if (this->tm_yday != that->tm_yday || this->tm_wday != that->tm_wday) { printf("mgtime fails [yw]day at %ld\n", t); printf("this = %d %d, ", this->tm_yday, this->tm_wday); printf("that = %d %d, ", that->tm_yday, that->tm_wday); } if (this->tm_isdst != that->tm_isdst) printf("mgtime fails dst at %ld\n", t); /* Test our mktime() */ his = kmtime(this); hat = mktime(that); if (hat != t) { printf("mktime fails at %04d-%02d-%02d %02d:%02d:%02d: ", this->tm_year+1900, this->tm_mon+1, this->tm_mday, this->tm_hour, this->tm_min, this->tm_sec); printf("hat = %ld, t = %ld\n", hat, t); } if (his != hat) { printf("kmtime fails at %04d-%02d-%02d %02d:%02d:%02d: ", this->tm_year+1900, this->tm_mon+1, this->tm_mday, this->tm_hour, this->tm_min, this->tm_sec); printf("his = %ld, hat = %ld, %f days\n", his, hat, (his - hat)/(24.0*60*60)); } } return 0; } #endif