📄 localtime.c
字号:
} } theirdstoffset = 0; for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; if (sp->ttis[j].tt_isdst) { theirdstoffset = -sp->ttis[j].tt_gmtoff; break; } } /* ** Initially we're assumed to be in standard time. */ isdst = FALSE; theiroffset = theirstdoffset; /* ** Now juggle transition times and types ** tracking offsets as you do. */ for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; sp->types[i] = sp->ttis[j].tt_isdst; if (sp->ttis[j].tt_ttisgmt) { /* No adjustment to transition time */ } else { /* ** If summer time is in effect, and the ** transition time was not specified as ** standard time, add the summer time ** offset to the transition time; ** otherwise, add the standard time ** offset to the transition time. */ /* ** Transitions from DST to DDST ** will effectively disappear since ** POSIX provides for only one DST ** offset. */ if (isdst && !sp->ttis[j].tt_ttisstd) { sp->ats[i] += dstoffset - theirdstoffset; } else { sp->ats[i] += stdoffset - theirstdoffset; } } theiroffset = -sp->ttis[j].tt_gmtoff; if (sp->ttis[j].tt_isdst) theirdstoffset = theiroffset; else theirstdoffset = theiroffset; } /* ** Finally, fill in ttis. ** ttisstd and ttisgmt need not be handled. */ sp->ttis[0].tt_gmtoff = -stdoffset; sp->ttis[0].tt_isdst = FALSE; sp->ttis[0].tt_abbrind = 0; sp->ttis[1].tt_gmtoff = -dstoffset; sp->ttis[1].tt_isdst = TRUE; sp->ttis[1].tt_abbrind = stdlen + 1; sp->typecnt = 2; } } else { dstlen = 0; sp->typecnt = 1; /* only standard time */ sp->timecnt = 0; sp->ttis[0].tt_gmtoff = -stdoffset; sp->ttis[0].tt_isdst = 0; sp->ttis[0].tt_abbrind = 0; } sp->charcnt = stdlen + 1; if (dstlen != 0) sp->charcnt += dstlen + 1; if ((size_t) sp->charcnt > sizeof sp->chars) return -1; cp = sp->chars; (void) strncpy(cp, stdname, stdlen); cp += stdlen; *cp++ = '\0'; if (dstlen != 0) { (void) strncpy(cp, dstname, dstlen); *(cp + dstlen) = '\0'; } return 0;}static int gmtload(struct state *sp){ if (tzload(gmt, sp, TRUE) != 0) return tzparse(gmt, sp, TRUE); else return -1;}static const struct state *ast_tzset(const char *zone){ struct state *sp; if (ast_strlen_zero(zone)) zone = "/etc/localtime"; AST_LIST_LOCK(&zonelist); AST_LIST_TRAVERSE(&zonelist, sp, list) { if (!strcmp(sp->name, zone)) { AST_LIST_UNLOCK(&zonelist); return sp; } } AST_LIST_UNLOCK(&zonelist); if (!(sp = ast_calloc(1, sizeof *sp))) return NULL; if (tzload(zone, sp, TRUE) != 0) { if (zone[0] == ':' || tzparse(zone, sp, FALSE) != 0) (void) gmtload(sp); } ast_copy_string(sp->name, zone, sizeof(sp->name)); AST_LIST_LOCK(&zonelist); AST_LIST_INSERT_TAIL(&zonelist, sp, list); AST_LIST_UNLOCK(&zonelist); return sp;}/*! \note** 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 ast_tm *localsub(const struct timeval *timep, const long offset, struct ast_tm *tmp, const struct state *sp){ const struct ttinfo * ttisp; int i; struct ast_tm * result; struct timeval t; memcpy(&t, timep, sizeof(t)); if (sp == NULL) return gmtsub(timep, offset, tmp); if ((sp->goback && t.tv_sec < sp->ats[0]) || (sp->goahead && t.tv_sec > sp->ats[sp->timecnt - 1])) { struct timeval newt = t; time_t seconds; time_t tcycles; int_fast64_t icycles; if (t.tv_sec < sp->ats[0]) seconds = sp->ats[0] - t.tv_sec; else seconds = t.tv_sec - sp->ats[sp->timecnt - 1]; --seconds; tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR; ++tcycles; icycles = tcycles; if (tcycles - icycles >= 1 || icycles - tcycles >= 1) return NULL; seconds = icycles; seconds *= YEARSPERREPEAT; seconds *= AVGSECSPERYEAR; if (t.tv_sec < sp->ats[0]) newt.tv_sec += seconds; else newt.tv_sec -= seconds; if (newt.tv_sec < sp->ats[0] || newt.tv_sec > sp->ats[sp->timecnt - 1]) return NULL; /* "cannot happen" */ result = localsub(&newt, offset, tmp, sp); if (result == tmp) { time_t newy; newy = tmp->tm_year; if (t.tv_sec < sp->ats[0]) newy -= icycles * YEARSPERREPEAT; else newy += icycles * YEARSPERREPEAT; tmp->tm_year = newy; if (tmp->tm_year != newy) return NULL; } return result; } if (sp->timecnt == 0 || t.tv_sec < sp->ats[0]) { i = 0; while (sp->ttis[i].tt_isdst) { if (++i >= sp->typecnt) { i = 0; break; } } } else { int lo = 1; int hi = sp->timecnt; while (lo < hi) { int mid = (lo + hi) >> 1; if (t.tv_sec < 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); tmp->tm_isdst = ttisp->tt_isdst;#ifndef SOLARIS /* Solaris doesn't have this element */ tmp->tm_gmtoff = ttisp->tt_gmtoff;#endif#ifdef TM_ZONE tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];#endif /* defined TM_ZONE */ tmp->tm_usec = timep->tv_usec; return result;}struct ast_tm *ast_localtime(const struct timeval *timep, struct ast_tm *tmp, const char *zone){ const struct state *sp = ast_tzset(zone); memset(tmp, 0, sizeof(*tmp)); return sp ? localsub(timep, 0L, tmp, sp) : NULL;}/*** This function provides informaton about daylight savings time ** for the given timezone. This includes whether it can determine ** if daylight savings is used for this timezone, the UTC times for ** when daylight savings transitions, and the offset in seconds from ** UTC. */void ast_get_dst_info(const time_t * const timep, int *dst_enabled, time_t *dst_start, time_t *dst_end, int *gmt_off, const char * const zone){ int i; int transition1 = -1; int transition2 = -1; time_t seconds; int bounds_exceeded = 0; time_t t = *timep; const struct state *sp; if (NULL == dst_enabled) return; *dst_enabled = 0; if (NULL == dst_start || NULL == dst_end || NULL == gmt_off) return; *gmt_off = 0; sp = ast_tzset(zone); if (NULL == sp) return; /* If the desired time exceeds the bounds of the defined time transitions * then give give up on determining DST info and simply look for gmt offset * This requires that I adjust the given time using increments of Gregorian * repeats to place the time within the defined time transitions in the * timezone structure. */ if ((sp->goback && t < sp->ats[0]) || (sp->goahead && t > sp->ats[sp->timecnt - 1])) { time_t tcycles; int_fast64_t icycles; if (t < sp->ats[0]) seconds = sp->ats[0] - t; else seconds = t - sp->ats[sp->timecnt - 1]; --seconds; tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR; ++tcycles; icycles = tcycles; if (tcycles - icycles >= 1 || icycles - tcycles >= 1) return; seconds = icycles; seconds *= YEARSPERREPEAT; seconds *= AVGSECSPERYEAR; if (t < sp->ats[0]) t += seconds; else t -= seconds; if (t < sp->ats[0] || t > sp->ats[sp->timecnt - 1]) return; /* "cannot happen" */ bounds_exceeded = 1; } if (sp->timecnt == 0 || t < sp->ats[0]) { /* I have no transition times or I'm before time */ *dst_enabled = 0; /* Find where I can get gmtoff */ i = 0; while (sp->ttis[i].tt_isdst) if (++i >= sp->typecnt) { i = 0; break; } *gmt_off = sp->ttis[i].tt_gmtoff; return; } for (i = 1; i < sp->timecnt; ++i) { if (t < sp->ats[i]) { transition1 = sp->types[i - 1]; transition2 = sp->types[i]; break; } } /* if I found transition times that do not bounded the given time and these correspond to or the bounding zones do not reflect a changes in day light savings, then I do not have dst active */ if (i >= sp->timecnt || 0 > transition1 || 0 > transition2 || (sp->ttis[transition1].tt_isdst == sp->ttis[transition2].tt_isdst)) { *dst_enabled = 0; *gmt_off = sp->ttis[sp->types[sp->timecnt -1]].tt_gmtoff; } else { /* I have valid daylight savings information. */ if(sp->ttis[transition2].tt_isdst) *gmt_off = sp->ttis[transition1].tt_gmtoff; else *gmt_off = sp->ttis[transition2].tt_gmtoff; /* If I adjusted the time earlier, indicate that the dst is invalid */ if (!bounds_exceeded) { *dst_enabled = 1; /* Determine which of the bounds is the start of daylight savings and which is the end */ if(sp->ttis[transition2].tt_isdst) { *dst_start = sp->ats[i]; *dst_end = sp->ats[i -1]; } else { *dst_start = sp->ats[i -1]; *dst_end = sp->ats[i]; } } } return;}/*** gmtsub is to gmtime as localsub is to localtime.*/static struct ast_tm *gmtsub(const struct timeval *timep, const long offset, struct ast_tm *tmp){ struct ast_tm * result; struct state *sp; AST_LIST_LOCK(&zonelist); AST_LIST_TRAVERSE(&zonelist, sp, list) { if (!strcmp(sp->name, "UTC")) break; } if (!sp) { if (!(sp = (struct state *) ast_calloc(1, sizeof *sp))) return NULL; gmtload(sp); AST_LIST_INSERT_TAIL(&zonelist, sp, list); } AST_LIST_UNLOCK(&zonelist); result = timesub(timep, offset, sp, tmp);#ifdef TM_ZONE /* ** Could get fancy here and deliver something such as ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero, ** but this is no time for a treasure hunt. */ if (offset != 0) tmp->TM_ZONE = " "; else tmp->TM_ZONE = sp->chars;#endif /* defined TM_ZONE */ return result;}/*! \brief** Return the number of leap years through the end of the given year** where, to make the math easy, the answer for year zero is defined as zero.*/static int leaps_thru_end_of(const int y){ return (y >= 0) ? (y / 4 - y / 100 + y / 400) : -(leaps_thru_end_of(-(y + 1)) + 1);}static struct ast_tm *timesub(const struct timeval *timep, const long offset, const struct state *sp, struct ast_tm *tmp){ const struct lsinfo * lp; time_t tdays; int idays; /* unsigned would be so 2003 */ long rem; int y; const int * ip; long corr; int hit; int i; long seconds; corr = 0; hit = 0; i = (sp == NULL) ? 0 : sp->leapcnt; while (--i >= 0) { lp = &sp->lsis[i]; if (timep->tv_sec >= lp->ls_trans) { if (timep->tv_sec == 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; } } y = EPOCH_YEAR; tdays = timep->tv_sec / SECSPERDAY; rem = timep->tv_sec - tdays * SECSPERDAY; while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { int newy; time_t tdelta; int idelta; int leapdays; tdelta = tdays / DAYSPERLYEAR; idelta = tdelta; if (tdelta - idelta >= 1 || idelta - tdelta >= 1) return NULL; if (idelta == 0) idelta = (tdays < 0) ? -1 : 1; newy = y; if (increment_overflow(&newy, idelta)) return NULL; leapdays = leaps_thru_end_of(newy - 1) - leaps_thru_end_of(y - 1); tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -