полная версия :)
/*******************************************************************************/
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);
}