108 lines
2.5 KiB
C
108 lines
2.5 KiB
C
#include "time_header.h"
|
|
|
|
struct tm * localsub(
|
|
struct state const *sp,
|
|
time_t const *timep,
|
|
int_fast32_t setname,
|
|
struct tm* const tmp
|
|
)
|
|
{
|
|
register const struct ttinfo* ttisp;
|
|
register int i;
|
|
register struct tm* result;
|
|
const time_t t = *timep;
|
|
|
|
if (sp == NULL) {
|
|
// Don't bother to set tzname etc.; tzset has already done it.
|
|
return gmtsub(gmtptr, timep, 0, tmp);
|
|
}
|
|
|
|
if ((sp->goback && t < sp->ats[0]) || (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
|
|
|
|
time_t newt = t;
|
|
register time_t seconds;
|
|
register time_t years;
|
|
|
|
if (t < sp->ats[0]) {
|
|
seconds = sp->ats[0] - t;
|
|
} else {
|
|
seconds = t - sp->ats[sp->timecnt - 1];
|
|
}
|
|
|
|
--seconds;
|
|
years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
|
|
seconds = years * AVGSECSPERYEAR;
|
|
|
|
if (t < sp->ats[0]) {
|
|
newt += seconds;
|
|
} else {
|
|
newt -= seconds;
|
|
}
|
|
|
|
if (newt < sp->ats[0] || newt > sp->ats[sp->timecnt - 1]) {
|
|
return NULL; // "cannot happen"
|
|
}
|
|
|
|
result = localsub(sp, &newt, setname, tmp);
|
|
|
|
if (result) {
|
|
int_fast64_t newy;
|
|
|
|
newy = result->tm_year;
|
|
if (t < sp->ats[0]) {
|
|
newy -= years;
|
|
} else {
|
|
newy += years;
|
|
}
|
|
|
|
if (! (INT_MIN <= newy && newy <= INT_MAX)) {
|
|
return NULL;
|
|
}
|
|
|
|
result->tm_year = newy;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
if (sp->timecnt == 0 || t < sp->ats[0]) {
|
|
i = sp->defaulttype;
|
|
} else {
|
|
|
|
register int lo = 1;
|
|
register int hi = sp->timecnt;
|
|
|
|
while (lo < hi) {
|
|
register int mid = (lo + hi) >> 1;
|
|
|
|
if (t < sp->ats[mid]) {
|
|
hi = mid;
|
|
} else {
|
|
lo = mid + 1;
|
|
}
|
|
}
|
|
|
|
i = (int) sp->types[lo - 1];
|
|
}
|
|
|
|
ttisp = &sp->ttis[i];
|
|
|
|
/*
|
|
** To get (wrong) behavior that's compatible with System V Release 2.0
|
|
** you'd replace the statement below with
|
|
** t += ttisp->tt_gmtoff;
|
|
** timesub(&t, 0L, sp, tmp);
|
|
*/
|
|
result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
|
|
|
|
if (result) {
|
|
result->tm_isdst = ttisp->tt_isdst;
|
|
result->tm_zone = (char *) &sp->chars[ttisp->tt_abbrind];
|
|
|
|
if (setname) {
|
|
update_tzname(sp, ttisp);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|