📄 localtime.cc
字号:
** n - day of year. ** Just add SECSPERDAY times the day number to the time of ** January 1, midnight, to get the day. */ value = janfirst + rulep->r_day * SECSPERDAY; break; case MONTH_NTH_DAY_OF_WEEK: /* ** Mm.n.d - nth "dth day" of month m. */ value = janfirst; for (i = 0; i < rulep->r_mon - 1; ++i) value += mon_lengths[leapyear][i] * SECSPERDAY; /* ** Use Zeller's Congruence to get day-of-week of first day of ** month. */ m1 = (rulep->r_mon + 9) % 12 + 1; yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; yy1 = yy0 / 100; yy2 = yy0 % 100; dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; if (dow < 0) dow += DAYSPERWEEK; /* ** "dow" is the day-of-week of the first day of the month. Get ** the day-of-month (zero-origin) of the first "dow" day of the ** month. */ d = rulep->r_day - dow; if (d < 0) d += DAYSPERWEEK; for (i = 1; i < rulep->r_week; ++i) { if (d + DAYSPERWEEK >= mon_lengths[leapyear][rulep->r_mon - 1]) break; d += DAYSPERWEEK; } /* ** "d" is the day-of-month (zero-origin) of the day we want. */ value += d * SECSPERDAY; break; } /* ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in ** question. To get the Epoch-relative time of the specified local ** time on that day, add the transition time and the current offset ** from UTC. */ return value + rulep->r_time + offset;}/*** Given a POSIX section 8-style TZ string, fill in the rule tables as** appropriate.*/static inttzparse(const char *name, struct state *sp, const int lastditch){ const char * stdname; const char * dstname; size_t stdlen; size_t dstlen; long stdoffset; long dstoffset; register time_t * atp; register unsigned char * typep; register char * cp; register int load_result; INITIALIZE(dstname); stdname = name; if (lastditch) { stdlen = strlen(name); /* length of standard zone name */ name += stdlen; if (stdlen >= sizeof sp->chars) stdlen = (sizeof sp->chars) - 1; stdoffset = 0; } else { name = getzname(name); stdlen = name - stdname; if (stdlen < 3) return -1; if (*name == '\0') return -1; name = getoffset(name, &stdoffset); if (name == NULL) return -1; } load_result = tzload(TZDEFRULES, sp); if (load_result != 0) sp->leapcnt = 0; /* so, we're off a little */ if (*name != '\0') { dstname = name; name = getzname(name); dstlen = name - dstname; /* length of DST zone name */ if (dstlen < 3) return -1; if (*name != '\0' && *name != ',' && *name != ';') { name = getoffset(name, &dstoffset); if (name == NULL) return -1; } else dstoffset = stdoffset - SECSPERHOUR; if (*name == ',' || *name == ';') { struct rule start; struct rule end; register int year; register time_t janfirst; time_t starttime; time_t endtime; ++name; if ((name = getrule(name, &start)) == NULL) return -1; if (*name++ != ',') return -1; if ((name = getrule(name, &end)) == NULL) return -1; if (*name != '\0') return -1; sp->typecnt = 2; /* standard time and DST */ /* ** Two transitions per year, from EPOCH_YEAR to 2037. */ sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); if (sp->timecnt > TZ_MAX_TIMES) return -1; sp->ttis[0].tt_gmtoff = -dstoffset; sp->ttis[0].tt_isdst = 1; sp->ttis[0].tt_abbrind = stdlen + 1; sp->ttis[1].tt_gmtoff = -stdoffset; sp->ttis[1].tt_isdst = 0; sp->ttis[1].tt_abbrind = 0; atp = sp->ats; typep = sp->types; janfirst = 0; for (year = EPOCH_YEAR; year <= 2037; ++year) { starttime = transtime(janfirst, year, &start, stdoffset); endtime = transtime(janfirst, year, &end, dstoffset); if (starttime > endtime) { *atp++ = endtime; *typep++ = 1; /* DST ends */ *atp++ = starttime; *typep++ = 0; /* DST begins */ } else { *atp++ = starttime; *typep++ = 0; /* DST begins */ *atp++ = endtime; *typep++ = 1; /* DST ends */ } janfirst += year_lengths[isleap(year)] * SECSPERDAY; } } else { register long theirstdoffset; register long theirdstoffset; register long theiroffset; register int isdst; register int i; register int j; if (*name != '\0') return -1; if (load_result != 0) return -1; /* ** Initial values of theirstdoffset and theirdstoffset. */ theirstdoffset = 0; for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; if (!sp->ttis[j].tt_isdst) { theirstdoffset = -sp->ttis[j].tt_gmtoff; break; } } 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 voidgmtload(struct state *sp){ if (tzload(gmt, sp) != 0) (void) tzparse(gmt, sp, TRUE);}#ifndef STD_INSPIRED/*** A non-static declaration of tzsetwall in a system header file** may cause a warning about this upcoming static declaration...*/static#endif /* !defined STD_INSPIRED */voidtzsetwall P((void)){ if (lcl_is_set < 0) return; lcl_is_set = -1;#ifdef ALL_STATE if (lclptr == NULL) { lclptr = (struct state *) malloc(sizeof *lclptr); if (lclptr == NULL) { settzname(); /* all we can do */ return; } }#endif /* defined ALL_STATE */#if defined (_WIN32) || defined (__CYGWIN__)#define is_upper(c) ((unsigned)(c) - 'A' <= 26) { TIME_ZONE_INFORMATION tz; char buf[BUFSIZ]; char *cp, *dst; wchar_t *src; div_t d; GetTimeZoneInformation(&tz); dst = cp = buf; for (src = tz.StandardName; *src; src++) if (is_upper(*src)) *dst++ = *src; if ((dst - cp) < 3) { /* In non-english Windows, converted tz.StandardName may not contain a valid standard timezone name. */ strcpy(cp, wildabbr); cp += strlen(wildabbr); } else cp = dst; d = div(tz.Bias+tz.StandardBias, 60); sprintf(cp, "%d", d.quot); if (d.rem) sprintf(cp=strchr(cp, 0), ":%d", abs(d.rem)); if(tz.StandardDate.wMonth) { cp = strchr(cp, 0); dst = cp; for (src = tz.DaylightName; *src; src++) if (is_upper(*src)) *dst++ = *src; if ((dst - cp) < 3) { /* In non-english Windows, converted tz.DaylightName may not contain a valid daylight timezone name. */ strcpy(cp, wildabbr); cp += strlen(wildabbr); } else cp = dst; d = div(tz.Bias+tz.DaylightBias, 60); sprintf(cp, "%d", d.quot); if (d.rem) sprintf(cp=strchr(cp, 0), ":%d", abs(d.rem)); cp = strchr(cp, 0); sprintf(cp=strchr(cp, 0), ",M%d.%d.%d/%d", tz.DaylightDate.wMonth, tz.DaylightDate.wDay, tz.DaylightDate.wDayOfWeek, tz.DaylightDate.wHour); if (tz.DaylightDate.wMinute || tz.DaylightDate.wSecond) sprintf(cp=strchr(cp, 0), ":%d", tz.DaylightDate.wMinute); if (tz.DaylightDate.wSecond) sprintf(cp=strchr(cp, 0), ":%d", tz.DaylightDate.wSecond); cp = strchr(cp, 0); sprintf(cp=strchr(cp, 0), ",M%d.%d.%d/%d", tz.StandardDate.wMonth, tz.StandardDate.wDay, tz.StandardDate.wDayOfWeek, tz.StandardDate.wHour); if (tz.StandardDate.wMinute || tz.StandardDate.wSecond) sprintf(cp=strchr(cp, 0), ":%d", tz.StandardDate.wMinute); if (tz.StandardDate.wSecond) sprintf(cp=strchr(cp, 0), ":%d", tz.StandardDate.wSecond); } /* printf("TZ deduced as `%s'\n", buf); */ if (tzparse(buf, lclptr, FALSE) == 0) { settzname(); setenv("TZ", buf, 1); return; } }#endif if (tzload((char *) NULL, lclptr) != 0) gmtload(lclptr); settzname();}extern "C" voidtzset P((void)){ const char * name = getenv("TZ"); if (name == NULL) { tzsetwall(); return; } if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) return; lcl_is_set = (strlen(name) < sizeof (lcl_TZname)); if (lcl_is_set) (void) strcpy(lcl_TZname, name);#ifdef ALL_STATE if (lclptr == NULL) { lclptr = (struct state *) malloc(sizeof *lclptr); if (lclptr == NULL) { settzname(); /* all we can do */ return; } }#endif /* defined ALL_STATE */ if (*name == '\0') { /* ** User wants it fast rather than right. */ lclptr->leapcnt = 0; /* so, we're off a little */ lclptr->timecnt = 0; 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) gmtload(lclptr); } settzname();}/*** 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.*//*ARGSUSED*/static voidlocalsub (const time_t * const timep, const long offset, struct tm * const tmp){ register struct state * sp; register const struct ttinfo * ttisp; register int i; const time_t t = *timep; sp = lclptr;#ifdef ALL_STATE if (sp == NULL) { gmtsub(timep, offset, tmp); return; }#endif /* defined ALL_STATE */ 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]; /* ** 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); */ timesub(&t, ttisp->tt_gmtoff, sp, tmp); tmp->tm_isdst = ttisp->tt_isdst; tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];#ifdef TM_ZONE tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];#endif /* defined TM_ZONE */}extern "C" struct tm *localtime(const time_t *timep){ tzset(); localsub(timep, 0L, &tm); return &tm;}/* * Re-entrant version of localtime */extern "C" struct tm *localtime_r(const time_t *timep, struct tm *tm){ localsub(timep, 0L, tm); return tm;}/*** gmtsub is to gmtime as localsub is to localtime.*/static voidgmtsub(const time_t *timep, const long offset, struct tm *tmp){ if (!gmt_is_set) { gmt_is_set = TRUE;#ifdef ALL_STATE gmtptr = (struct state *) malloc(sizeof *gmtptr); if (gmtptr != NULL)#endif /* defined ALL_STATE */ gmtload(gmtptr); } timesub(timep, offset, gmtptr, 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 = wildabbr; else {#ifdef ALL_STATE if (gmtptr == NULL) tmp->TM_ZONE = gmt; else tmp->TM_ZONE = gmtptr->chars;#endif /* defined ALL_STATE */#ifndef ALL_STATE tmp->TM_ZONE = gmtptr->chars;#endif /* State Farm */ }#endif /* defined TM_ZONE */}extern "C" struct tm *gmtime(const time_t *timep){ gmtsub(timep, 0L, &tm); return &tm;}/* * Re-entrant version of gmtime
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -