📄 time.c
字号:
/* 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 *localtime_r(register const time_t *__restrict timer, register struct tm *__restrict result){ time_t x[1]; long offset; int days, dst; TZLOCK; tzset(); dst = 0; do { days = -7; offset = 604800L - _time_tzinfo[dst].gmt_offset; if (*timer > (LONG_MAX - 604800L)) { days = -days; offset = -offset; } *x = *timer + offset; _time_t2tm(x, days, result); if (dst) { result->tm_isdst = dst; break; } ++dst; } while ((result->tm_isdst = tm_isdst(result)) != 0); TZUNLOCK; return result;}#endif/**********************************************************************/#ifdef L_mktimetime_t mktime(struct tm *timeptr){ return _time_mktime(timeptr, 1);}#endif/**********************************************************************/#ifdef L_strftime#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 4size_t strftime(char *__restrict s, size_t maxsize, const char *__restrict format, const struct tm *__restrict timeptr){ long tzo; register const char *p; register const char *o; const rule_struct *rsp; 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 = nl_langinfo(_NL_ITEM(LC_TIME, (int)(((unsigned char *)p)[4])) ))) ) { p = o; goto LOOP; }#endif p = nl_langinfo(_NL_ITEM(LC_TIME, (int)(*((unsigned char *)p)))); 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; } TZLOCK; rsp = _time_tzinfo; if (timeptr->tm_isdst > 0) { ++rsp; } if (*p == 'Z') { o = rsp->tzname; assert(o != NULL);#if 0 if (!o) { /* PARANOIA */ o = spec+30; /* empty string */ }#endif o_count = SIZE_MAX; TZUNLOCK; goto OUTPUT; } else { /* z */ *s = '+'; if ((tzo = -rsp->gmt_offset) < 0) { tzo = -tzo; *s = '-'; } 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 { i = TP_OFFSETS + (code & 0x1f); if ((field_val = load_field(spec[i],timeptr)) < 0) { goto OUTPUT; } i = spec[i+(TP_CODES - TP_OFFSETS)]; j = (i & 128) ? 100: 12; if (i & 64) { field_val /= j;; } if (i & 32) { field_val %= j;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -