time_t _DEFUN(mktime, (tim_p), struct tm *tim_p) { time_t tim = 0; long days = 0; int year, isdst; __tzinfo_type *tz = __gettzinfo (); /* validate structure */ validate_structure (tim_p); /* compute hours, minutes, seconds */ tim += tim_p->tm_sec + (tim_p->tm_min * _SEC_IN_MINUTE) + (tim_p->tm_hour * _SEC_IN_HOUR); /* compute days in year */ days += tim_p->tm_mday - 1; days += _DAYS_BEFORE_MONTH[tim_p->tm_mon]; if (tim_p->tm_mon > 1 && _DAYS_IN_YEAR (tim_p->tm_year) == 366) days++; /* compute day of the year */ tim_p->tm_yday = days; if (tim_p->tm_year > 10000 || tim_p->tm_year < -10000) return (time_t) -1; /* compute days in other years */ year = tim_p->tm_year; if (year > 70) { for (year = 70; year < tim_p->tm_year; year++) days += _DAYS_IN_YEAR (year); } else if (year < 70) { for (year = 69; year > tim_p->tm_year; year--) days -= _DAYS_IN_YEAR (year); days -= _DAYS_IN_YEAR (year); } /* compute total seconds */ tim += (days * _SEC_IN_DAY); TZ_LOCK; /* put time in gmt format */ /* also convenient since tzcalc's change in this format */ tim += (time_t) tz->__tzrule[0].offset; if (_daylight) { int y = tim_p->tm_year + YEAR_BASE; /* check for years >= 1970 or if already calculated change times */ if (y == tz->__tzyear || __tzcalc_limits (y)) { int total_diff = 0; /* calculate the DST add-in value (negate) */ time_t diff = tz->__tzrule[1].offset - tz->__tzrule[0].offset; isdst = tim_p->tm_isdst; /* POSIX states if a positive supplied presume DST in effect */ if (isdst >= 1) { /* remove DST added into our initial struct time calculations */ tim += diff; /* indicate removal */ total_diff += (int) diff; } /* preload gmt formatted zone change times */ time_t startstd = tz->__tzrule[1].change; time_t startdst = tz->__tzrule[0].change; /* (isdst >= 1) converted to STD, * (isdst == 0) is STD, * (isdst < 0) let it ride as a STD guess */ isdst = 0; if (((tz->__tznorth) && (tim >= startdst && tim < startstd)) || (!(tz->__tznorth) && (tim >= startdst || tim < startstd))) { /* update removal by indicating DST needed for struct add in */ total_diff -= (int) diff; isdst = 1; } /* if presumed and is dst than no change, else change */ if (total_diff) { tim_p->tm_sec += total_diff; /* save mday, need to update yday and wday if roll over * validate_structure() doesn't handle these */ total_diff = tim_p->tm_mday; validate_structure(tim_p); total_diff = tim_p->tm_mday - total_diff; /* roll over occurred */ if (total_diff) { /* compensate for month roll overs */ if (total_diff > 1) total_diff = -1; else if (total_diff < -1) total_diff = 1; /* update days for mday calculation */ days += (long)total_diff; /* handle yday */ if ((tim_p->tm_yday += total_diff) < 0) { --year; tim_p->tm_yday = _DAYS_IN_YEAR(year) - 1; } else { total_diff = _DAYS_IN_YEAR(year); if (tim_p->tm_yday > (total_diff - 1)) tim_p->tm_yday -= total_diff; } } } } else /* year fell before 1970, no calculations performed */ /* we return an isdst of 0, the "put time in gmt format" makes this STD */ isdst = 0; } else /* global indicated only STD exists */ isdst = 0; TZ_UNLOCK; /* reset isdst flag to what we have calculated */ tim_p->tm_isdst = isdst; /* compute day of the week */ if ((tim_p->tm_wday = (days + 4) % 7) < 0) tim_p->tm_wday += 7; return tim; }