📄 localtime.cc
字号:
*/extern "C" struct tm *gmtime_r(const time_t *timep, struct tm *tm){ gmtsub(timep, 0L, tm); return tm;}#ifdef STD_INSPIREDextern "C" struct tm *offtime(const time_t *timep, const long offset){ gmtsub(timep, offset, &tm); return &tm;}#endif /* defined STD_INSPIRED */static voidtimesub(const time_t *timep, const long offset, const struct state *sp, struct tm *tmp){ register const struct lsinfo * lp; register long days; register long rem; register int y; register int yleap; register const int * ip; register long corr; register int hit; register int i; corr = 0; hit = 0;#ifdef ALL_STATE i = (sp == NULL) ? 0 : sp->leapcnt;#endif /* defined ALL_STATE */#ifndef ALL_STATE i = sp->leapcnt;#endif /* State Farm */ while (--i >= 0) { lp = &sp->lsis[i]; if (*timep >= lp->ls_trans) { if (*timep == lp->ls_trans) { hit = ((i == 0 && lp->ls_corr > 0) || lp->ls_corr > sp->lsis[i - 1].ls_corr); if (hit) while (i > 0 && sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 && sp->lsis[i].ls_corr == sp->lsis[i - 1].ls_corr + 1) { ++hit; --i; } } corr = lp->ls_corr; break; } } days = *timep / SECSPERDAY; rem = *timep % SECSPERDAY;#ifdef mc68k if (*timep == 0x80000000) { /* ** A 3B1 muffs the division on the most negative number. */ days = -24855; rem = -11648; }#endif /* defined mc68k */ rem += (offset - corr); 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); /* ** A positive leap second requires a special ** representation. This uses "... ??:59:60" et seq. */ tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); if (tmp->tm_wday < 0) tmp->tm_wday += DAYSPERWEEK; y = EPOCH_YEAR;#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { register int newy; newy = y + days / DAYSPERNYEAR; if (days < 0) --newy; days -= (newy - y) * DAYSPERNYEAR + LEAPS_THRU_END_OF(newy - 1) - LEAPS_THRU_END_OF(y - 1); y = newy; } 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;#ifdef TM_GMTOFF tmp->TM_GMTOFF = offset;#endif /* defined TM_GMTOFF */}extern "C" char *ctime(const time_t *timep){/*** Section 4.12.3.2 of X3.159-1989 requires that** The ctime function converts the calendar time pointed to by timer** to local time in the form of a string. It is equivalent to** asctime(localtime(timer))*/ return asctime(localtime(timep));}extern "C" char *ctime_r(const time_t *timep, char *buf){ struct tm tm; return asctime_r(localtime_r(timep, &tm), buf);}/*** 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.** [kridle@xinet.com as of 1996-01-16.]** 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 *//*** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).*/static intincrement_overflow(int *number, int delta){ int number0; number0 = *number; *number += delta; return (*number < number0) != (delta < 0);}static intnormalize_overflow(int *tensptr, int *unitsptr, const int base){ register int tensdelta; tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); *unitsptr -= tensdelta * base; return increment_overflow(tensptr, tensdelta);}static inttmcomp(register const struct tm *atmp, register const struct tm *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_ttime2sub(struct tm *tmp, void (*funcp) P((const time_t*, long, struct tm*)), const long offset, int *okayp, const int do_norm_secs){ 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 (do_norm_secs) { if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN)) return WRONG; } if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) return WRONG; if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) return WRONG; if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) return WRONG; /* ** Turn yourtm.tm_year into an actual year number for now. ** It is converted back to an offset from TM_YEAR_BASE later. */ if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) return WRONG; while (yourtm.tm_mday <= 0) { if (increment_overflow(&yourtm.tm_year, -1)) return WRONG; i = yourtm.tm_year + (1 < yourtm.tm_mon); yourtm.tm_mday += year_lengths[isleap(i)]; } while (yourtm.tm_mday > DAYSPERLYEAR) { i = yourtm.tm_year + (1 < yourtm.tm_mon); yourtm.tm_mday -= year_lengths[isleap(i)]; if (increment_overflow(&yourtm.tm_year, 1)) return WRONG; } for ( ; ; ) { i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; if (yourtm.tm_mday <= i) break; yourtm.tm_mday -= i; if (++yourtm.tm_mon >= MONSPERYEAR) { yourtm.tm_mon = 0; if (increment_overflow(&yourtm.tm_year, 1)) return WRONG; } } if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) return WRONG; if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { /* ** We can't set tm_sec to 0, because that might push the ** time below the minimum representable time. ** Set tm_sec to 59 instead. ** This assumes that the minimum representable time is ** not in the same minute that a leap second was deleted from, ** which is a safer assumption than using 58 would be. */ if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) return WRONG; saved_seconds = yourtm.tm_sec; yourtm.tm_sec = SECSPERMIN - 1; } else { saved_seconds = yourtm.tm_sec; yourtm.tm_sec = 0; } /* ** Divide the search space in half ** (this works whether time_t is signed or unsigned). */ bits = TYPE_BIT(time_t) - 1; /* ** If time_t is signed, then 0 is just above the median, ** assuming two's complement arithmetic. ** If time_t is unsigned, then (1 << bits) is just above the median. */ t = TYPE_SIGNED(time_t) ? 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; /* may be needed if new t is minimal */ 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. */ /* ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. */ sp = (const struct state *) (((void *) funcp == (void *) localsub) ? lclptr : gmtptr);#ifdef ALL_STATE if (sp == NULL) return WRONG;#endif /* defined ALL_STATE */ for (i = sp->typecnt - 1; i >= 0; --i) { if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) continue; for (j = sp->typecnt - 1; j >= 0; --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: newt = t + saved_seconds; if ((newt < t) != (saved_seconds < 0)) return WRONG; t = newt; (*funcp)(&t, offset, tmp); *okayp = TRUE; return t;}static time_ttime2(struct tm *tmp, void (*funcp) P((const time_t*, long, struct tm*)), const long offset, int *okayp){ time_t t; /* ** First try without normalization of seconds ** (in case tm_sec contains a value associated with a leap second). ** If that fails, try with normalization of seconds. */ t = time2sub(tmp, funcp, offset, okayp, FALSE); return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);}static time_ttime1(struct tm *tmp, void (*funcp) P((const time_t *, long, struct tm *)), 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);#ifdef PCTS /* ** PCTS code courtesy Grant Sullivan (grant@osf.org). */ if (okay) return t; if (tmp->tm_isdst < 0) tmp->tm_isdst = 0; /* reset to std and try again */#endif /* defined PCTS */#ifndef PCTS if (okay || tmp->tm_isdst < 0) return t;#endif /* !defined PCTS */ /* ** 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. */ /* ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. */ sp = (const struct state *) (((void *) funcp == (void *) localsub) ? lclptr : gmtptr);#ifdef ALL_STATE if (sp == NULL) return WRONG;#endif /* defined ALL_STATE */ for (samei = sp->typecnt - 1; samei >= 0; --samei) { if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) continue; for (otheri = sp->typecnt - 1; otheri >= 0; --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;}extern "C" time_tmktime(struct tm *tmp){ tzset(); return time1(tmp, localsub, 0L);}#ifdef STD_INSPIREDextern "C" time_ttimelocal(struct tm *tmp){ tmp->tm_isdst = -1; /* in case it wasn't initialized */ return mktime(tmp);}extern "C" time_ttimegm(struct tm *tmp){ tmp->tm_isdst = 0; return time1(tmp, gmtsub, 0L);}extern "C" time_ttimeoff(struct tm *tmp, const long offset){ tmp->tm_isdst = 0; return time1(tmp, gmtsub, offset);}#endif /* defined STD_INSPIRED */#ifdef CMUCS/*** The following is supplied for compatibility with** previous versions of the CMUCS runtime library.*/extern "C" longgtime(struct tm *tmp){ const time_t t = mktime(tmp); if (t == WRONG) return -1; return t;}#endif /* defined CMUCS *//*** XXX--is the below the right way to conditionalize??*/#ifdef STD_INSPIRED/*** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which** is not the case if we are accounting for leap seconds.** So, we provide the following conversion routines for use** when exchanging timestamps with POSIX conforming systems.*/static longleapcorr(time_t *timep){ register struct state * sp; register struct lsinfo * lp; register int i; sp = lclptr; i = sp->leapcnt; while (--i >= 0) { lp = &sp->lsis[i]; if (*timep >= lp->ls_trans) return lp->ls_corr; } return 0;}extern "C" time_ttime2posix(time_t t){ tzset(); return t - leapcorr(&t);}extern "C" time_tposix2time(time_t t){ time_t x; time_t y; tzset(); /* ** For a positive leap second hit, the result ** is not unique. For a negative leap second ** hit, the corresponding time doesn't exist, ** so we return an adjacent second. */ x = t + leapcorr(&t); y = x - leapcorr(&x); if (y < t) { do { x++; y = x - leapcorr(&x); } while (y < t); if (t != y) return x - 1; } else if (y > t) { do { --x; y = x - leapcorr(&x); } while (y > t); if (t != y) return x + 1; } return x;}#endif /* defined STD_INSPIRED */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -