📄 time.c
字号:
strcpy(p->tzname, key); return p->tzname; } } /* Either invalid or couldn't alloc. */ return ll_tzname[1].tzname;}#endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */static const unsigned char day_cor[] = { /* non-leap */ 31, 31, 34, 34, 35, 35, 36, 36, 36, 37, 37, 38, 38/* 0, 0, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7 *//* 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */};/* Note: timezone locking is done by localtime_r. */static int tm_isdst(register const struct tm *__restrict ptm, register rule_struct *r){ long sec; int i, isdst, isleap, day, day0, monlen, mday; int oday; /* Note: oday can be uninitialized. */ isdst = 0; if (r[1].tzname[0] != 0) { /* First, get the current seconds offset from the start of the year. * Fields of ptm are assumed to be in their normal ranges. */ sec = ptm->tm_sec + 60 * (ptm->tm_min + 60 * (long)(ptm->tm_hour + 24 * ptm->tm_yday)); /* Do some prep work. */ i = (ptm->tm_year % 400) + 1900; /* Make sure we don't overflow. */ isleap = __isleap(i); --i; day0 = (1 + i /* Normal years increment 1 wday. */ + (i/4) - (i/100) + (i/400) ) % 7; i = 0; do { day = r->day; /* Common for 'J' and # case. */ if (r->rule_type == 'J') { if (!isleap || (day < (31+29))) { --day; } } else if (r->rule_type == 'M') { /* Find 0-based day number for 1st of the month. */ day = 31*r->month - day_cor[r->month -1]; if (isleap && (day >= 59)) { ++day; } monlen = 31 + day_cor[r->month -1] - day_cor[r->month]; if (isleap && (r->month > 1)) { ++monlen; } /* Wweekday (0 is Sunday) of 1st of the month * is (day0 + day) % 7. */ if ((mday = r->day - ((day0 + day) % 7)) >= 0) { mday -= 7; /* Back up into prev month since r->week>0. */ } if ((mday += 7 * r->week) >= monlen) { mday -= 7; } /* So, 0-based day number is... */ day += mday; } if (i != 0) { /* Adjust sec since dst->std change time is in dst. */ sec += (r[-1].gmt_offset - r->gmt_offset); if (oday > day) { ++isdst; /* Year starts in dst. */ } } oday = day; /* Now convert day to seconds and add offset and compare. */ if (sec >= (day * 86400L) + r->dst_offset) { ++isdst; } ++r; } while (++i < 2); } return (isdst & 1);}struct tm *__time_localtime_tzi(register const time_t *__restrict timer, register struct tm *__restrict result, rule_struct *tzi){ time_t x[1]; long offset; int days, dst; dst = 0; do { days = -7; offset = 604800L - tzi[dst].gmt_offset; if (*timer > (LONG_MAX - 604800L)) { days = -days; offset = -offset; } *x = *timer + offset; _time_t2tm(x, days, result); result->tm_isdst = dst;#ifdef __UCLIBC_HAS_TM_EXTENSIONS__ result->tm_gmtoff = - tzi[dst].gmt_offset; result->tm_zone = lookup_tzname(tzi[dst].tzname);#endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */ } while ((++dst < 2) && ((result->tm_isdst = tm_isdst(result, tzi)) != 0)); return result;}#endif/**********************************************************************/#ifdef L_mktime/* Another name for `mktime'. *//* time_t timelocal(struct tm *tp) */weak_alias(mktime,timelocal);time_t mktime(struct tm *timeptr){ return _time_mktime(timeptr, 1);}#endif/**********************************************************************/#ifdef L_timegm/* Like `mktime' but timeptr represents Universal Time, not local time. */time_t timegm(struct tm *timeptr){ rule_struct gmt_tzinfo[2]; memset(gmt_tzinfo, 0, sizeof(gmt_tzinfo)); strcpy(gmt_tzinfo[0].tzname, "GMT"); /* Match glibc behavior here. */ return _time_mktime_tzi(timeptr, 1, gmt_tzinfo);}#endif/**********************************************************************/#if defined(L_strftime) || defined(L_strftime_l)#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)size_t strftime(char *__restrict s, size_t maxsize, const char *__restrict format, const struct tm *__restrict timeptr){ return __strftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);}#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */#define NO_E_MOD 0x80#define NO_O_MOD 0x40#define ILLEGAL_SPEC 0x3f#define INT_SPEC 0x00 /* must be 0x00!! */#define STRING_SPEC 0x10 /* must be 0x10!! */#define CALC_SPEC 0x20#define STACKED_SPEC 0x30#define MASK_SPEC 0x30/* Compatibility: * * No alternate digit (%O?) handling. Always uses 0-9. * Alternate locale format (%E?) handling is broken for nontrivial ERAs. * glibc's %P is currently faked by %p. This means it doesn't do lower case. * glibc's %k, %l, and %s are handled. * glibc apparently allows (and ignores) extraneous 'E' and 'O' modifiers, * while they are flagged as illegal conversions here. *//* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */static const unsigned char spec[] = { /* A */ 0x03 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* B */ 0x04 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* C */ 0x0a | INT_SPEC | NO_O_MOD, /* D */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* F */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* G */ 0x03 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* H */ 0x0b | INT_SPEC | NO_E_MOD, /* I */ 0x0c | INT_SPEC | NO_E_MOD, /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* M */ 0x0d | INT_SPEC | NO_E_MOD, /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* P */ 0x05 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc ; use %p */ /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* R */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* S */ 0x0e | INT_SPEC | NO_E_MOD, /* T */ 0x05 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* U */ 0x04 | CALC_SPEC | NO_E_MOD, /* V */ 0x05 | CALC_SPEC | NO_E_MOD, /* W */ 0x06 | CALC_SPEC | NO_E_MOD, /* X */ 0x0a | STACKED_SPEC | NO_O_MOD, /* Y */ 0x0f | INT_SPEC | NO_O_MOD, /* Z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD, '?', /* 26 */ '?', /* 27 */ '?', /* 28 */ '?', /* 29 */ 0, /* 30 */ 0, /* 31 */ /* a */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* c */ 0x08 | STACKED_SPEC | NO_O_MOD, /* d */ 0x00 | INT_SPEC | NO_E_MOD, /* e */ 0x01 | INT_SPEC | NO_E_MOD, /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* g */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* same as b */ /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* j */ 0x08 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* k */ 0x03 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */ /* l */ 0x04 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */ /* m */ 0x05 | INT_SPEC | NO_E_MOD, /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* p */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* s */ 0x07 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */ /* t */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* u */ 0x07 | INT_SPEC | NO_E_MOD, /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD, /* w */ 0x02 | INT_SPEC | NO_E_MOD, /* x */ 0x09 | STACKED_SPEC | NO_O_MOD, /* y */ 0x09 | INT_SPEC, /* z */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* WARNING!!! These are dependent on the layout of struct tm!!! */#define FIELD_MAX (26+6+26) 60 /* 61? */, 59, 23, 31, 11, 0 /* 9999 */, 6, 0 /* 365 */,#define TP_OFFSETS (FIELD_MAX+8) 3, /* d */ 3, /* e */ 6, /* w */ 2, /* k */ 2, /* l */ 4, /* m */ 0, /* CURRENTLY UNUSED */ /* NOTE: u,j,y order must be preserved as 6,7,5 seq is used in the code! */#define CALC_OFFSETS (TP_OFFSETS + 7) 6, /* u */ 7, /* j */ 5, /* y */ 5, /* C */ 2, /* H */ 2, /* I */ 1, /* M */ 0, /* S */ 5, /* Y */ 6, /* a */ 4, /* b, h */ 2, /* p */ 6, /* A */ 4, /* B */ 2, /* P */#define TP_CODES (TP_OFFSETS + 16 + 6) 2 | 16, /* d */ 2, /* e */ 0 | 16, /* w */ 2, /* k */ 2 | 32 | 0, /* l */ 2 | 16 | 1, /* m */ 0, /* CURRENTLY UNUSED */ 0 | 16 | 8 , /* u */ 4 | 16 | 1, /* j */ 2 | 128 | 32 | 16 , /* y */ 2 | 128 | 64 | 32 | 16 , /* C */ 2 | 16, /* H */ 2 | 32 | 16 | 0, /* I */ 2 | 16, /* M */ 2 | 16, /* S */ 6 | 16, /* Y */ 2, /* a */ 2, /* b, h */ 2 | 64, /* p */ 2, /* A */ 2, /* B */ 2 | 64, /* P */#define STRINGS_NL_ITEM_START (TP_CODES + 16 + 6) _NL_ITEM_INDEX(ABDAY_1), /* a */ _NL_ITEM_INDEX(ABMON_1), /* b, h */ _NL_ITEM_INDEX(AM_STR), /* p */ _NL_ITEM_INDEX(DAY_1), /* A */ _NL_ITEM_INDEX(MON_1), /* B */ _NL_ITEM_INDEX(AM_STR), /* P -- wrong! need lower case */#define STACKED_STRINGS_START (STRINGS_NL_ITEM_START+6) 6, 7, 8, 16, 24, 29, /* 6 - offsets from offset-count to strings */ '\n', 0, /* 2 */ '\t', 0, /* 2 */ '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */ '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */ '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/ '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */#define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 43) _NL_ITEM_INDEX(D_T_FMT), /* c */ _NL_ITEM_INDEX(D_FMT), /* x */ _NL_ITEM_INDEX(T_FMT), /* X */ _NL_ITEM_INDEX(T_FMT_AMPM), /* r */#ifdef ENABLE_ERA_CODE _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */ _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */ _NL_ITEM_INDEX(ERA_T_FMT), /* EX */#endif};static int load_field(int k, const struct tm *__restrict timeptr){ int r; int r_max; r = ((int *) timeptr)[k]; r_max = spec[FIELD_MAX + k]; if (k == 7) { r_max = 365; } else if (k == 5) { r += 1900; r_max = 9999; } if ((((unsigned int) r) > r_max) || ((k == 3) && !r)) { r = -1; } return r;}#define MAX_PUSH 4#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Check multibyte format string validity.#endifsize_t __XL(strftime)(char *__restrict s, size_t maxsize, const char *__restrict format, const struct tm *__restrict timeptr __LOCALE_PARAM ){ long tzo; register const char *p; register const char *o;#ifndef __UCLIBC_HAS_TM_EXTENSIONS__ const rule_struct *rsp;#endif const char *stack[MAX_PUSH]; size_t count; size_t o_count; int field_val, i, j, lvl; int x[3]; /* wday, yday, year */ int isofm, days; char buf[__UIM_BUFLEN_LONG]; unsigned char mod; unsigned char code; tzset(); /* We'll, let's get this out of the way. */ lvl = 0; p = format; count = maxsize; LOOP: if (!count) { return 0; } if (!*p) { if (lvl == 0) { *s = 0; /* nul-terminate */ return maxsize - count; } p = stack[--lvl]; goto LOOP; } o_count = 1; if ((*(o = p) == '%') && (*++p != '%')) { o_count = 2; mod = ILLEGAL_SPEC; if ((*p == 'O') || (*p == 'E')) { /* modifier */ mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD); ++o_count; ++p; } if ((((unsigned char)(((*p) | 0x20) - 'a')) >= 26) || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC) ) { if (!*p) { --p; --o_count; } goto OUTPUT; } code &= ILLEGAL_SPEC; /* modifiers are preserved in mod var. */ if ((code & MASK_SPEC) == STACKED_SPEC) { if (lvl == MAX_PUSH) { goto OUTPUT; /* Stack full so treat as illegal spec. */ } stack[lvl++] = ++p; if ((code &= 0xf) < 8) { p = ((const char *) spec) + STACKED_STRINGS_START + code; p += *((unsigned char *)p); goto LOOP; } p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START + (code & 7);#ifdef ENABLE_ERA_CODE if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */ && (*(o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, (int)(((unsigned char *)p)[4])) __LOCALE_ARG ))) ) { p = o; goto LOOP; }#endif p = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, (int)(*((unsigned char *)p))) __LOCALE_ARG ); goto LOOP; } o = spec + 26; /* set to "????" */ if ((code & MASK_SPEC) == CALC_SPEC) { if (*p == 's') { time_t t; /* Use a cast to silence the warning since *timeptr won't * be changed. */ if ((t = _time_mktime((struct tm *) timeptr, 0)) == ((time_t) -1) ) { o_count = 1; goto OUTPUT; }#ifdef TIME_T_IS_UNSIGNED o = _uintmaxtostr(buf + sizeof(buf) - 1, (uintmax_t) t, 10, __UIM_DECIMAL);#else o = _uintmaxtostr(buf + sizeof(buf) - 1, (uintmax_t) t, -10, __UIM_DECIMAL);#endif o_count = sizeof(buf); goto OUTPUT; } else if (((*p) | 0x20) == 'z') { /* 'z' or 'Z' */ if (timeptr->tm_isdst < 0) { /* SUSv3 specifies this behavior for 'z', but we'll also * treat it as "no timezone info" for 'Z' too. */ o_count = 0; goto OUTPUT; }#ifdef __UCLIBC_HAS_TM_EXTENSIONS__#define RSP_TZUNLOCK ((void) 0)#define RSP_TZNAME timeptr->tm_zone#define RSP_GMT_OFFSET timeptr->tm_gmtoff#else#define RSP_TZUNLOCK TZUNLOCK#define RSP_TZNAME rsp->tzname#define RSP_GMT_OFFSET rsp->gmt_offset TZLOCK; rsp = _time_tzinfo; if (timeptr->tm_isdst > 0) { ++rsp; }#endif if (*p == 'Z') { o = RSP_TZNAME; assert(o != NULL);#if 0 if (!o) { /* PARANOIA */ o = spec+30; /* empty string */ }#endif o_count = SIZE_MAX; RSP_TZUNLOCK; goto OUTPUT; } else { /* z */ *s = '+'; if ((tzo = -RSP_GMT_OFFSET) < 0) { tzo = -tzo; *s = '-'; } RSP_TZUNLOCK; ++s; --count; i = tzo / 60; field_val = ((i / 60) * 100) + (i % 60); i = 16 + 6; /* 0-fill, width = 4 */ } } else { /* TODO: don't need year for U, W */ for (i=0 ; i < 3 ; i++) { if ((x[i] = load_field(spec[CALC_OFFSETS+i],timeptr)) < 0) { goto OUTPUT; } } i = 16 + 2; /* 0-fill, width = 2 */ if ((*p == 'U') || (*p == 'W')) { field_val = ((x[1] - x[0]) + 7); if (*p == 'W') { ++field_val; } field_val /= 7; if ((*p == 'W') && !x[0]) { --field_val; } } else { /* ((*p == 'g') || (*p == 'G') || (*p == 'V')) */ ISO_LOOP: isofm = (((x[1] - x[0]) + 11) % 7) - 3; /* [-3,3] */ if (x[1] < isofm) { /* belongs to previous year */ --x[2]; x[1] += 365 + __isleap(x[2]); goto ISO_LOOP; } field_val = ((x[1] - isofm) / 7) + 1; /* week # */ days = 365 + __isleap(x[2]); isofm = ((isofm + 7*53 + 3 - days)) %7 + days - 3; /* next year */ if (x[1] >= isofm) { /* next year */ x[1] -= days; ++x[2]; goto ISO_LOOP; } if (*p != 'V') { /* need year */ field_val = x[2]; /* TODO: what if x[2] now 10000 ?? */ if (*p == 'g') { field_val %= 100; } else { i = 16 + 6; /* 0-fill, width = 4 */ } } } } } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -