amiga-tz/library/time_localsub.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;
}