📄 localtime.c
字号:
if (lclptr == NULL) {#ifdef S5EMUL settzname(); /* all we can do */#endif return; } } if (tzload((char *) NULL, lclptr) != 0) gmtload(lclptr);#ifdef S5EMUL settzname();#endif}voidtzset(){ register const char * name; name = getenv("TZ"); if (name == NULL) { tzsetwall(); return; } lcl_is_set = TRUE; if (lclptr == NULL) { lclptr = (struct state *) calloc(1, (unsigned)sizeof *lclptr); if (lclptr == NULL) {#ifdef S5EMUL settzname(); /* all we can do */#endif return; } } if (*name == '\0') { /* ** User wants it fast rather than right. */ lclptr->timecnt = 0; lclptr->typecnt = 1; lclptr->charcnt = sizeof GMT; if (allocall(lclptr) < 0) return; lclptr->ttis[0].tt_gmtoff = 0; lclptr->ttis[0].tt_abbrind = 0; (void) strcpy(lclptr->chars, GMT); } else if (tzload(name, lclptr) != 0) if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) (void) tzparse(name, lclptr, TRUE);#ifdef S5EMUL settzname();#endif}/*** The easy way to behave "as if no library function calls" localtime** is to not call it--so we drop its guts into "localsub", which can be** freely called. (And no, the PANS doesn't require the above behavior--** but it *is* desirable.)**** The unused offset argument is for the benefit of mktime variants.*/static struct tm tm;/*ARGSUSED*/static voidlocalsub(timep, offset, tmp)const time_t * const timep;const long offset;struct tm * const tmp;{ register const struct state * sp; register const struct ttinfo * ttisp; register int i; const time_t t = *timep; if (!lcl_is_set) tzset(); sp = lclptr; if (sp == NULL) { gmtsub(timep, offset, tmp); return; } if (sp->timecnt == 0 || t < sp->ats[0]) { i = 0; while (sp->ttis[i].tt_isdst) if (++i >= sp->typecnt) { i = 0; break; } } else { for (i = 1; i < sp->timecnt; ++i) if (t < sp->ats[i]) break; i = sp->types[i - 1]; } ttisp = &sp->ttis[i]; timesub(&t, ttisp->tt_gmtoff, tmp); tmp->tm_isdst = ttisp->tt_isdst;#ifdef S5EMUL tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];#endif /* S5EMUL */ tmp->tm_zone = &sp->chars[ttisp->tt_abbrind];}struct tm *localtime(timep)const time_t * const timep;{ localsub(timep, 0L, &tm); return &tm;}/*** gmtsub is to gmtime as localsub is to localtime.*/static voidgmtsub(timep, offset, tmp)const time_t * const timep;const long offset;struct tm * const tmp;{ if (!gmt_is_set) { gmt_is_set = TRUE; gmtptr = (struct state *) calloc(1, (unsigned)sizeof *gmtptr); if (gmtptr != NULL) gmtload(gmtptr); } timesub(timep, offset, tmp); /* ** Could get fancy here and deliver something such as ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, ** but this is no time for a treasure hunt. */ if (offset != 0) tmp->tm_zone = WILDABBR; else { if (gmtptr == NULL) tmp->tm_zone = GMT; else tmp->tm_zone = gmtptr->chars; }}struct tm *gmtime(timep)const time_t * const timep;{ gmtsub(timep, 0L, &tm); return &tm;}struct tm *offtime(timep, offset)const time_t * const timep;const long offset;{ gmtsub(timep, offset, &tm); return &tm;}static voidtimesub(timep, offset, tmp)const time_t * const timep;const long offset;register struct tm * const tmp;{ register long days; register long rem; register int y; register int yleap; register const int * ip; days = *timep / SECSPERDAY; rem = *timep % SECSPERDAY; rem += offset; while (rem < 0) { rem += SECSPERDAY; --days; } while (rem >= SECSPERDAY) { rem -= SECSPERDAY; ++days; } tmp->tm_hour = (int) (rem / SECSPERHOUR); rem = rem % SECSPERHOUR; tmp->tm_min = (int) (rem / SECSPERMIN); tmp->tm_sec = (int) (rem % SECSPERMIN); tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); if (tmp->tm_wday < 0) tmp->tm_wday += DAYSPERWEEK; y = EPOCH_YEAR; if (days >= 0) for ( ; ; ) { yleap = isleap(y); if (days < (long) year_lengths[yleap]) break; ++y; days = days - (long) year_lengths[yleap]; } else do { --y; yleap = isleap(y); days = days + (long) year_lengths[yleap]; } while (days < 0); tmp->tm_year = y - TM_YEAR_BASE; tmp->tm_yday = (int) days; ip = mon_lengths[yleap]; for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) days = days - (long) ip[tmp->tm_mon]; tmp->tm_mday = (int) (days + 1); tmp->tm_isdst = 0; tmp->tm_gmtoff = offset;}/*** Adapted from code provided by Robert Elz, who writes:** The "best" way to do mktime I think is based on an idea of Bob** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).** It does a binary search of the time_t space. Since time_t's are** just 32 bits, its a max of 32 iterations (even at 64 bits it** would still be very reasonable).*/#ifndef WRONG#define WRONG (-1)#endif /* !defined WRONG */static voidnormalize(tensptr, unitsptr, base)int * const tensptr;int * const unitsptr;const int base;{ if (*unitsptr >= base) { *tensptr += *unitsptr / base; *unitsptr %= base; } else if (*unitsptr < 0) { --*tensptr; *unitsptr += base; if (*unitsptr < 0) { *tensptr -= 1 + (-*unitsptr) / base; *unitsptr = base - (-*unitsptr) % base; } }}static inttmcomp(atmp, btmp)register const struct tm * const atmp;register const struct tm * const btmp;{ register int result; if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && (result = (atmp->tm_min - btmp->tm_min)) == 0) result = atmp->tm_sec - btmp->tm_sec; return result;}static time_ttime2(tmp, funcp, offset, okayp)struct tm * const tmp;void (* const funcp)();const long offset;int * const okayp;{ register const struct state * sp; register int dir; register int bits; register int i, j ; register int saved_seconds; time_t newt; time_t t; struct tm yourtm, mytm; *okayp = FALSE; yourtm = *tmp; if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR); normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY); normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR); while (yourtm.tm_mday <= 0) { --yourtm.tm_year; yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)]; } for ( ; ; ) { i = mon_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)][yourtm.tm_mon]; if (yourtm.tm_mday <= i) break; yourtm.tm_mday -= i; if (++yourtm.tm_mon >= MONSPERYEAR) { yourtm.tm_mon = 0; ++yourtm.tm_year; } } saved_seconds = yourtm.tm_sec; yourtm.tm_sec = 0; /* ** Calculate the number of magnitude bits in a time_t ** (this works regardless of whether time_t is ** signed or unsigned, though lint complains if unsigned). */ for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) ; /* ** If time_t is signed, then 0 is the median value, ** if time_t is unsigned, then 1 << bits is median. */ t = (t < 0) ? 0 : ((time_t) 1 << bits); for ( ; ; ) { (*funcp)(&t, offset, &mytm); dir = tmcomp(&mytm, &yourtm); if (dir != 0) { if (bits-- < 0) return WRONG; if (bits < 0) --t; else if (dir > 0) t -= (time_t) 1 << bits; else t += (time_t) 1 << bits; continue; } if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) break; /* ** Right time, wrong type. ** Hunt for right time, right type. ** It's okay to guess wrong since the guess ** gets checked. */ sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); if (sp == NULL) return WRONG; for (i = 0; i < sp->typecnt; ++i) { if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) continue; for (j = 0; j < sp->typecnt; ++j) { if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) continue; newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; (*funcp)(&newt, offset, &mytm); if (tmcomp(&mytm, &yourtm) != 0) continue; if (mytm.tm_isdst != yourtm.tm_isdst) continue; /* ** We have a match. */ t = newt; goto label; } } return WRONG; }label: t += saved_seconds; (*funcp)(&t, offset, tmp); *okayp = TRUE; return t;}static time_ttime1(tmp, funcp, offset)struct tm * const tmp;void (* const funcp)();const long offset;{ register time_t t; register const struct state * sp; register int samei, otheri; int okay; if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; t = time2(tmp, funcp, offset, &okay); if (okay || tmp->tm_isdst < 0) return t; /* ** We're supposed to assume that somebody took a time of one type ** and did some math on it that yielded a "struct tm" that's bad. ** We try to divine the type they started from and adjust to the ** type they need. */ sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); if (sp == NULL) return WRONG; for (samei = 0; samei < sp->typecnt; ++samei) { if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) continue; for (otheri = 0; otheri < sp->typecnt; ++otheri) { if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) continue; tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; t = time2(tmp, funcp, offset, &okay); if (okay) return t; tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; } } return WRONG;}time_tmktime(tmp)struct tm * const tmp;{ return time1(tmp, localsub, 0L);}time_ttimelocal(tmp)struct tm * const tmp;{ tmp->tm_isdst = -1; return mktime(tmp);}time_ttimegm(tmp)struct tm * const tmp;{ return time1(tmp, gmtsub, 0L);}time_ttimeoff(tmp, offset)struct tm * const tmp;const long offset;{ return time1(tmp, gmtsub, offset);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -