📄 localtime.c
字号:
tdays -= leapdays; y = newy; } seconds = tdays * SECSPERDAY + 0.5; tdays = seconds / SECSPERDAY; rem += seconds - tdays * SECSPERDAY; /* ** Given the range, we can now fearlessly cast... */ idays = tdays; rem += offset - corr; while (rem < 0) { rem += SECSPERDAY; --idays; } while (rem >= SECSPERDAY) { rem -= SECSPERDAY; ++idays; } while (idays < 0) { if (increment_overflow(&y, -1)) return NULL; idays += year_lengths[isleap(y)]; } while (idays >= year_lengths[isleap(y)]) { idays -= year_lengths[isleap(y)]; if (increment_overflow(&y, 1)) return NULL; } tmp->tm_year = y; if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE)) return NULL; tmp->tm_yday = idays; /* ** The "extra" mods below avoid overflow problems. */ tmp->tm_wday = EPOCH_WDAY + ((y - EPOCH_YEAR) % DAYSPERWEEK) * (DAYSPERNYEAR % DAYSPERWEEK) + leaps_thru_end_of(y - 1) - leaps_thru_end_of(EPOCH_YEAR - 1) + idays; tmp->tm_wday %= DAYSPERWEEK; if (tmp->tm_wday < 0) tmp->tm_wday += DAYSPERWEEK; tmp->tm_hour = (int) (rem / SECSPERHOUR); 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; ip = mon_lengths[isleap(y)]; for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) idays -= ip[tmp->tm_mon]; tmp->tm_mday = (int) (idays + 1); tmp->tm_isdst = 0;#ifdef TM_GMTOFF tmp->TM_GMTOFF = offset;#endif /* defined TM_GMTOFF */ tmp->tm_usec = timep->tv_usec; return tmp;}/*! \note** 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.** 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).*//*! \brief** Simplified normalize logic courtesy Paul Eggert.*/static int increment_overflow(int *number, int delta){ int number0; number0 = *number; *number += delta; return (*number < number0) != (delta < 0);}static int long_increment_overflow(long *number, int delta){ long number0; number0 = *number; *number += delta; return (*number < number0) != (delta < 0);}static int normalize_overflow(int *tensptr, int *unitsptr, const int base){ int tensdelta; tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); *unitsptr -= tensdelta * base; return increment_overflow(tensptr, tensdelta);}static int long_normalize_overflow(long *tensptr, int *unitsptr, const int base){ int tensdelta; tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); *unitsptr -= tensdelta * base; return long_increment_overflow(tensptr, tensdelta);}static int tmcomp(const struct ast_tm *atmp, const struct ast_tm *btmp){ 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)) == 0) result = atmp->tm_usec - btmp->tm_usec; return result;}static struct timeval time2sub(struct ast_tm *tmp, struct ast_tm * (* const funcp) (const struct timeval *, long, struct ast_tm *, const struct state *), const long offset, int *okayp, const int do_norm_secs, const struct state *sp){ int dir; int i, j; int saved_seconds; long li; time_t lo; time_t hi; long y; struct timeval newt = { 0, 0 }; struct timeval t = { 0, 0 }; struct ast_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; y = yourtm.tm_year; if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR)) return WRONG; /* ** Turn y into an actual year number for now. ** It is converted back to an offset from TM_YEAR_BASE later. */ if (long_increment_overflow(&y, TM_YEAR_BASE)) return WRONG; while (yourtm.tm_mday <= 0) { if (long_increment_overflow(&y, -1)) return WRONG; li = y + (1 < yourtm.tm_mon); yourtm.tm_mday += year_lengths[isleap(li)]; } while (yourtm.tm_mday > DAYSPERLYEAR) { li = y + (1 < yourtm.tm_mon); yourtm.tm_mday -= year_lengths[isleap(li)]; if (long_increment_overflow(&y, 1)) return WRONG; } for ( ; ; ) { i = mon_lengths[isleap(y)][yourtm.tm_mon]; if (yourtm.tm_mday <= i) break; yourtm.tm_mday -= i; if (++yourtm.tm_mon >= MONSPERYEAR) { yourtm.tm_mon = 0; if (long_increment_overflow(&y, 1)) return WRONG; } } if (long_increment_overflow(&y, -TM_YEAR_BASE)) return WRONG; yourtm.tm_year = y; if (yourtm.tm_year != y) return WRONG; if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) saved_seconds = 0; else if (y + 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; } /* ** Do a binary search (this works whatever time_t's type is). */ if (!TYPE_SIGNED(time_t)) { lo = 0; hi = lo - 1; } else if (!TYPE_INTEGRAL(time_t)) { if (sizeof(time_t) > sizeof(float)) hi = (time_t) DBL_MAX; else hi = (time_t) FLT_MAX; lo = -hi; } else { lo = 1; for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i) lo *= 2; hi = -(lo + 1); } for ( ; ; ) { t.tv_sec = lo / 2 + hi / 2; if (t.tv_sec < lo) t.tv_sec = lo; else if (t.tv_sec > hi) t.tv_sec = hi; if ((*funcp)(&t, offset, &mytm, sp) == NULL) { /* ** Assume that t is too extreme to be represented in ** a struct ast_tm; arrange things so that it is less ** extreme on the next pass. */ dir = (t.tv_sec > 0) ? 1 : -1; } else dir = tmcomp(&mytm, &yourtm); if (dir != 0) { if (t.tv_sec == lo) { ++t.tv_sec; if (t.tv_sec <= lo) return WRONG; ++lo; } else if (t.tv_sec == hi) { --t.tv_sec; if (t.tv_sec >= hi) return WRONG; --hi; } if (lo > hi) return WRONG; if (dir > 0) hi = t.tv_sec; else lo = t.tv_sec; 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. */ 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.tv_sec = t.tv_sec + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; if ((*funcp)(&newt, offset, &mytm, sp) == NULL) continue; 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.tv_sec = t.tv_sec + saved_seconds; if ((newt.tv_sec < t.tv_sec) != (saved_seconds < 0)) return WRONG; t.tv_sec = newt.tv_sec; if ((*funcp)(&t, offset, tmp, sp)) *okayp = TRUE; return t;}static struct timeval time2(struct ast_tm *tmp, struct ast_tm * (* const funcp) (const struct timeval *, long, struct ast_tm*, const struct state *sp), const long offset, int *okayp, const struct state *sp){ struct timeval t; /*! \note ** 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, sp); return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);}static struct timeval time1(struct ast_tm *tmp, struct ast_tm * (* const funcp) (const struct timeval *, long, struct ast_tm *, const struct state *), const long offset, const struct state *sp){ struct timeval t; int samei, otheri; int sameind, otherind; int i; int nseen; int seen[TZ_MAX_TYPES]; int types[TZ_MAX_TYPES]; int okay; if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; t = time2(tmp, funcp, offset, &okay, sp);#ifdef PCTS /* ** PCTS code courtesy Grant Sullivan. */ 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 ast_tm" that's bad. ** We try to divine the type they started from and adjust to the ** type they need. */ if (sp == NULL) return WRONG; for (i = 0; i < sp->typecnt; ++i) seen[i] = FALSE; nseen = 0; for (i = sp->timecnt - 1; i >= 0; --i) if (!seen[sp->types[i]]) { seen[sp->types[i]] = TRUE; types[nseen++] = sp->types[i]; } for (sameind = 0; sameind < nseen; ++sameind) { samei = types[sameind]; if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) continue; for (otherind = 0; otherind < nseen; ++otherind) { otheri = types[otherind]; 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, sp); 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;}struct timeval ast_mktime(struct ast_tm *tmp, const char *zone){ const struct state *sp; if (!(sp = ast_tzset(zone))) return WRONG; return time1(tmp, localsub, 0L, sp);}int ast_strftime(char *buf, size_t len, const char *tmp, const struct ast_tm *tm){ size_t fmtlen = strlen(tmp) + 1; char *format = ast_calloc(1, fmtlen), *fptr = format, *newfmt; int decimals = -1, i, res; long fraction; if (!format) return -1; for (; *tmp; tmp++) { if (*tmp == '%') { switch (tmp[1]) { case '1': case '2': case '3': case '4': case '5': case '6': if (tmp[2] != 'q') goto defcase; decimals = tmp[1] - '0'; tmp++; /* Fall through */ case 'q': /* Milliseconds */ if (decimals == -1) decimals = 3; /* Juggle some memory to fit the item */ newfmt = ast_realloc(format, fmtlen + decimals); if (!newfmt) { ast_free(format); return -1; } fptr = fptr - format + newfmt; format = newfmt; fmtlen += decimals; /* Reduce the fraction of time to the accuracy needed */ for (i = 6, fraction = tm->tm_usec; i > decimals; i--) fraction /= 10; fptr += sprintf(fptr, "%0*ld", decimals, fraction); /* Reset, in case more than one 'q' specifier exists */ decimals = -1; tmp++; break; default: goto defcase; } } elsedefcase: *fptr++ = *tmp; } *fptr = '\0';#undef strftime res = (int)strftime(buf, len, format, (struct tm *)tm); ast_free(format); return res;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -