полная версия :)
/*******************************************************************************/ typedef struct { int tm_sec; /* seconds after the minute - [0,59] */ int tm_min; /* minutes after the hour - [0,59] */ int tm_hour; /* hours since midnight - [0,23] */ int tm_mday; /* day of the month - [1,31] */ int tm_mon; /* months since January - [0,11] */ int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday - [0,6] */ int tm_yday; /* days since January 1 - [0,365] */ int tm_isdst; /* daylight savings time flag */ } tm; extern tm xTimeAndDate; /*******************************************************************************/ int gmtime32(unsigned long timp, tm *ptm); unsigned long makegmtime32(tm *tb); #define _DAY_SEC (24L * 60L * 60L) /* secs in a day */ #define _YEAR_SEC (365L * _DAY_SEC) /* secs in a year */ #define _FOUR_YEAR_SEC (1461L * _DAY_SEC) /* secs in a 4 year interval */ #define _DEC_SEC 315532800L /* secs in 1970-1979 */ #define _BASE_YEAR 70L /* 1970 is the base year */ #define _BASE_DOW 4L /* 01-01-70 was a Thursday */ #define _LEAP_YEAR_ADJUST 17L /* Leap years 1900 - 1970 */ #define _MAX_YEAR 138L /* 2038 is the max year */ /* * Macro to determine if a given year, expressed as the number of years since * 1900, is a leap year. */ #define _IS_LEAP_YEAR(y) (((y % 4 == 0) && (y % 100 != 0)) || ((y + 1900) % 400 == 0)) /* * Number of leap years from 1970 up to, but not including, the specified year * (expressed as the number of years since 1900). */ #define _ELAPSED_LEAP_YEARS(y) (((y - 1)/4) - ((y - 1)/100) + ((y + 299)/400) - _LEAP_YEAR_ADJUST) const int _lpdays[] = {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; const int _days[] = {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364}; tm xTimeAndDate; int gmtime32(unsigned long timp, tm *ptm){ unsigned long caltim; /* = *timp; *//* calendar time to convert */ int islpyr = 0; /* is-current-year-a-leap-year flag */ int tmptim; int* mdays; /* pointer to days or lpdays */ tm* ptb = ptm; memset( ptm, 0xff, sizeof(tm)); caltim = timp; /* * Determine years since 1970. First, identify the four-year interval * since this makes handling leap-years easy (note that 2000 IS a * leap year and 2100 is out-of-range). */ tmptim = (int)(caltim /_FOUR_YEAR_SEC); caltim -= ((unsigned long)tmptim * _FOUR_YEAR_SEC); /* * Determine which year of the interval */ tmptim = (tmptim * 4) + 70; /* 1970, 1974, 1978,...,etc. */ if ( caltim >= _YEAR_SEC ) { tmptim++; /* 1971, 1975, 1979,...,etc. */ caltim -= _YEAR_SEC; if ( caltim >= _YEAR_SEC ) { tmptim++; /* 1972, 1976, 1980,...,etc. */ caltim -= _YEAR_SEC; /* * Note, it takes 366 days-worth of seconds to get past a leap * year. */ if ( caltim >= (_YEAR_SEC + _DAY_SEC) ) { tmptim++; /* 1973, 1977, 1981,...,etc. */ caltim -= (_YEAR_SEC + _DAY_SEC); } else { /* * In a leap year after all, set the flag. */ islpyr++; } } } /* * tmptim now holds the value for tm_year. caltim now holds the * number of elapsed seconds since the beginning of that year. */ ptb->tm_year = tmptim; /* * Determine days since January 1 (0 - 365). This is the tm_yday value. * Leave caltim with number of elapsed seconds in that day. */ ptb->tm_yday = (int)(caltim / _DAY_SEC); caltim -= (unsigned long)(ptb->tm_yday) * _DAY_SEC; /* * Determine months since January (0 - 11) and day of month (1 - 31) */ if (islpyr) mdays = _lpdays; else mdays = _days; for (tmptim = 1 ; mdays[tmptim] < ptb->tm_yday ; tmptim++); ptb->tm_mon = --tmptim; ptb->tm_mday = ptb->tm_yday - mdays[tmptim]; /* * Determine days since Sunday (0 - 6) */ ptb->tm_wday = ((int)(timp / _DAY_SEC) + _BASE_DOW) % 7; /* * Determine hours since midnight (0 - 23), minutes after the hour * (0 - 59), and seconds after the minute (0 - 59). */ ptb->tm_hour = (int)(caltim / 3600); caltim -= (unsigned long)ptb->tm_hour * 3600L; ptb->tm_min = (int)(caltim / 60); ptb->tm_sec = (int)(caltim - (ptb->tm_min) * 60); ptb->tm_isdst = 0; return 0; } /* * ChkAdd evaluates to TRUE if dest = src1 + src2 has overflowed */ #define ChkAdd(dest, src1, src2) ( ((src1 >= 0L) && (src2 >= 0L) && (dest < 0L)) || ((src1 < 0L) && (src2 < 0L) && (dest >= 0L)) ) /* * ChkMul evaluates to TRUE if dest = src1 * src2 has overflowed */ #define ChkMul(dest, src1, src2) ( src1 ? (dest/src1 != src2) : 0 ) unsigned long makegmtime32(tm *tb){ unsigned long tmptm1, tmptm2, tmptm3; tm tbtemp; long dstbias = 0; long timezone = 0; /* * First, make sure tm_year is reasonably close to being in range. */ if ( ((tmptm1 = tb->tm_year) < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1) ) goto err_mktime; /* * Adjust month value so it is in the range 0 - 11. This is because * we don't know how many days are in months 12, 13, 14, etc. */ if ( (tb->tm_mon < 0) || (tb->tm_mon > 11) ) { /* * no danger of overflow because the range check above. */ tmptm1 += (tb->tm_mon / 12); if ( (tb->tm_mon %= 12) < 0 ) { tb->tm_mon += 12; tmptm1--; } /* * Make sure year count is still in range. */ if ( (tmptm1 < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1) ) goto err_mktime; } /***** HERE: tmptm1 holds number of elapsed years *****/ /* * Calculate days elapsed minus one, in the given year, to the given * month. Check for leap year and adjust if necessary. */ tmptm2 = _days[tb->tm_mon]; if ( !(tmptm1 & 3) && (tb->tm_mon > 1) ) tmptm2++; /* * Calculate elapsed days since base date (midnight, 1/1/70, UTC) * * * 365 days for each elapsed year since 1970, plus one more day for * each elapsed leap year. no danger of overflow because of the range * check (above) on tmptm1. */ tmptm3 = (tmptm1 - _BASE_YEAR) * 365L + ((tmptm1 - 1L) >> 2) - _LEAP_YEAR_ADJUST; /* * elapsed days to current month (still no possible overflow) */ tmptm3 += tmptm2; /* * elapsed days to current date. overflow is now possible. */ tmptm1 = tmptm3 + (tmptm2 = (unsigned long)(tb->tm_mday)); if ( ChkAdd(tmptm1, tmptm3, tmptm2) ) goto err_mktime; /***** HERE: tmptm1 holds number of elapsed days *****/ /* * Calculate elapsed hours since base date */ tmptm2 = tmptm1 * 24L; if ( ChkMul(tmptm2, tmptm1, 24L) ) goto err_mktime; tmptm1 = tmptm2 + (tmptm3 = (unsigned long)tb->tm_hour); if ( ChkAdd(tmptm1, tmptm2, tmptm3) ) goto err_mktime; /***** HERE: tmptm1 holds number of elapsed hours *****/ /* * Calculate elapsed minutes since base date */ tmptm2 = tmptm1 * 60L; if ( ChkMul(tmptm2, tmptm1, 60L) ) goto err_mktime; tmptm1 = tmptm2 + (tmptm3 = (unsigned long)tb->tm_min); if ( ChkAdd(tmptm1, tmptm2, tmptm3) ) goto err_mktime; /***** HERE: tmptm1 holds number of elapsed minutes *****/ /* * Calculate elapsed seconds since base date */ tmptm2 = tmptm1 * 60L; if ( ChkMul(tmptm2, tmptm1, 60L) ) goto err_mktime; tmptm1 = tmptm2 + (tmptm3 = (unsigned long)tb->tm_sec); if ( ChkAdd(tmptm1, tmptm2, tmptm3) ) goto err_mktime; /***** HERE: tmptm1 holds number of elapsed seconds *****/ if ( gmtime32(tmptm1, &tbtemp) != 0 ) goto err_mktime; /***** HERE: tmptm1 holds number of elapsed seconds, adjusted *****/ /***** for local time if requested *****/ *tb = tbtemp; return (unsigned long)tmptm1; err_mktime: /* * All errors come to here */ return (unsigned long)(-1); }