?? getdate.c
字號(hào):
to_year (textint textyear){ int year = textyear.value; if (year < 0) year = -year; /* XPG4 suggests that years 00-68 map to 2000-2068, and years 69-99 map to 1969-1999. */ if (textyear.digits == 2) year += year < 69 ? 2000 : 1900; return year;}static table const *lookup_zone (parser_control const *pc, char const *name){ table const *tp; /* Try local zone abbreviations first; they're more likely to be right. */ for (tp = pc->local_time_zone_table; tp->name; tp++) if (strcmp (name, tp->name) == 0) return tp; for (tp = time_zone_table; tp->name; tp++) if (strcmp (name, tp->name) == 0) return tp; return 0;}#if ! HAVE_TM_GMTOFF/* Yield the difference between *A and *B, measured in seconds, ignoring leap seconds. The body of this function is taken directly from the GNU C Library; see src/strftime.c. */static inttm_diff (struct tm const *a, struct tm const *b){ /* Compute intervening leap days correctly even if year is negative. Take care to avoid int overflow in leap day calculations, but it's OK to assume that A and B are close to each other. */ int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3); int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3); int a100 = a4 / 25 - (a4 % 25 < 0); int b100 = b4 / 25 - (b4 % 25 < 0); int a400 = a100 >> 2; int b400 = b100 >> 2; int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); int years = a->tm_year - b->tm_year; int days = (365 * years + intervening_leap_days + (a->tm_yday - b->tm_yday)); return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) + (a->tm_min - b->tm_min)) + (a->tm_sec - b->tm_sec));}#endif /* ! HAVE_TM_GMTOFF */static table const *lookup_word (parser_control const *pc, char *word){ char *p; char *q; size_t wordlen; table const *tp; int i; int abbrev; /* Make it uppercase. */ for (p = word; *p; p++) if (ISLOWER ((unsigned char) *p)) *p = toupper ((unsigned char) *p); for (tp = meridian_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; /* See if we have an abbreviation for a month. */ wordlen = strlen (word); abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.'); for (tp = month_and_day_table; tp->name; tp++) if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0) return tp; if ((tp = lookup_zone (pc, word))) return tp; if (strcmp (word, dst_table[0].name) == 0) return dst_table; for (tp = time_units_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; /* Strip off any plural and try the units table again. */ if (word[wordlen - 1] == 'S') { word[wordlen - 1] = '\0'; for (tp = time_units_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; word[wordlen - 1] = 'S'; /* For "this" in relative_time_table. */ } for (tp = relative_time_table; tp->name; tp++) if (strcmp (word, tp->name) == 0) return tp; /* Military time zones. */ if (wordlen == 1) for (tp = military_table; tp->name; tp++) if (word[0] == tp->name[0]) return tp; /* Drop out any periods and try the time zone table again. */ for (i = 0, p = q = word; (*p = *q); q++) if (*q == '.') i = 1; else p++; if (i && (tp = lookup_zone (pc, word))) return tp; return 0;}static intyylex (YYSTYPE *lvalp, parser_control *pc){ unsigned char c; int count; for (;;) { while (c = *pc->input, ISSPACE (c)) pc->input++; if (ISDIGIT (c) || c == '-' || c == '+') { char const *p; int sign; int value; if (c == '-' || c == '+') { sign = c == '-' ? -1 : 1; c = *++pc->input; if (! ISDIGIT (c)) /* skip the '-' sign */ continue; } else sign = 0; p = pc->input; value = 0; do { value = 10 * value + c - '0'; c = *++p; } while (ISDIGIT (c)); lvalp->textintval.value = sign < 0 ? -value : value; lvalp->textintval.digits = p - pc->input; pc->input = p; return sign ? tSNUMBER : tUNUMBER; } if (ISALPHA (c)) { char buff[20]; char *p = buff; table const *tp; do { if (p < buff + sizeof buff - 1) *p++ = c; c = *++pc->input; } while (ISALPHA (c) || c == '.'); *p = '\0'; tp = lookup_word (pc, buff); if (! tp) return '?'; lvalp->intval = tp->value; return tp->type; } if (c != '(') return *pc->input++; count = 0; do { c = *pc->input++; if (c == '\0') return c; if (c == '(') count++; else if (c == ')') count--; } while (count > 0); }}/* Do nothing if the parser reports an error. */static intyyerror (char *s ATTRIBUTE_UNUSED){ return 0;}/* Parse a date/time string P. Return the corresponding time_t value, or (time_t) -1 if there is an error. P can be an incomplete or relative time specification; if so, use *NOW as the basis for the returned time. */time_tget_date (const char *p, const time_t *now){ time_t Start = now ? *now : time (0); struct tm *tmp = localtime (&Start); struct tm tm; struct tm tm0; parser_control pc; if (! tmp) return -1; pc.input = p; pc.year.value = tmp->tm_year + TM_YEAR_BASE; pc.year.digits = 4; pc.month = tmp->tm_mon + 1; pc.day = tmp->tm_mday; pc.hour = tmp->tm_hour; pc.minutes = tmp->tm_min; pc.seconds = tmp->tm_sec; tm.tm_isdst = tmp->tm_isdst; pc.meridian = MER24; pc.rel_seconds = 0; pc.rel_minutes = 0; pc.rel_hour = 0; pc.rel_day = 0; pc.rel_month = 0; pc.rel_year = 0; pc.dates_seen = 0; pc.days_seen = 0; pc.rels_seen = 0; pc.times_seen = 0; pc.local_zones_seen = 0; pc.zones_seen = 0;#if HAVE_TM_ZONE pc.local_time_zone_table[0].name = tmp->tm_zone; pc.local_time_zone_table[0].type = tLOCAL_ZONE; pc.local_time_zone_table[0].value = tmp->tm_isdst; pc.local_time_zone_table[1].name = 0; /* Probe the names used in the next three calendar quarters, looking for a tm_isdst different from the one we already have. */ { int quarter; for (quarter = 1; quarter <= 3; quarter++) { time_t probe = Start + quarter * (90 * 24 * 60 * 60); struct tm *probe_tm = localtime (&probe); if (probe_tm && probe_tm->tm_zone && probe_tm->tm_isdst != pc.local_time_zone_table[0].value) { { pc.local_time_zone_table[1].name = probe_tm->tm_zone; pc.local_time_zone_table[1].type = tLOCAL_ZONE; pc.local_time_zone_table[1].value = probe_tm->tm_isdst; pc.local_time_zone_table[2].name = 0; } break; } } }#else#if HAVE_TZNAME {# ifndef tzname extern char *tzname[];# endif int i; for (i = 0; i < 2; i++) { pc.local_time_zone_table[i].name = tzname[i]; pc.local_time_zone_table[i].type = tLOCAL_ZONE; pc.local_time_zone_table[i].value = i; } pc.local_time_zone_table[i].name = 0; }#else pc.local_time_zone_table[0].name = 0;#endif#endif if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name && ! strcmp (pc.local_time_zone_table[0].name, pc.local_time_zone_table[1].name)) { /* This locale uses the same abbrevation for standard and daylight times. So if we see that abbreviation, we don't know whether it's daylight time. */ pc.local_time_zone_table[0].value = -1; pc.local_time_zone_table[1].name = 0; } if (yyparse (&pc) != 0 || 1 < pc.times_seen || 1 < pc.dates_seen || 1 < pc.days_seen || 1 < (pc.local_zones_seen + pc.zones_seen) || (pc.local_zones_seen && 1 < pc.local_isdst)) return -1; tm.tm_year = to_year (pc.year) - TM_YEAR_BASE + pc.rel_year; tm.tm_mon = pc.month - 1 + pc.rel_month; tm.tm_mday = pc.day + pc.rel_day; if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen)) { tm.tm_hour = to_hour (pc.hour, pc.meridian); if (tm.tm_hour < 0) return -1; tm.tm_min = pc.minutes; tm.tm_sec = pc.seconds; } else { tm.tm_hour = tm.tm_min = tm.tm_sec = 0; } /* Let mktime deduce tm_isdst if we have an absolute time stamp, or if the relative time stamp mentions days, months, or years. */ if (pc.dates_seen | pc.days_seen | pc.times_seen | pc.rel_day | pc.rel_month | pc.rel_year) tm.tm_isdst = -1; /* But if the input explicitly specifies local time with or without DST, give mktime that information. */ if (pc.local_zones_seen) tm.tm_isdst = pc.local_isdst; tm0 = tm; Start = mktime (&tm); if (Start == (time_t) -1) { /* Guard against falsely reporting errors near the time_t boundaries when parsing times in other time zones. For example, if the min time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead of UTC, then the min localtime value is 1970-01-01 08:00:00; if we apply mktime to 1970-01-01 00:00:00 we will get an error, so we apply mktime to 1970-01-02 08:00:00 instead and adjust the time zone by 24 hours to compensate. This algorithm assumes that there is no DST transition within a day of the time_t boundaries. */ if (pc.zones_seen) { tm = tm0; if (tm.tm_year <= EPOCH_YEAR - TM_YEAR_BASE) { tm.tm_mday++; pc.time_zone += 24 * 60; } else { tm.tm_mday--; pc.time_zone -= 24 * 60; } Start = mktime (&tm); } if (Start == (time_t) -1) return Start; } if (pc.days_seen && ! pc.dates_seen) { tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7 + 7 * (pc.day_ordinal - (0 < pc.day_ordinal))); tm.tm_isdst = -1; Start = mktime (&tm); if (Start == (time_t) -1) return Start; } if (pc.zones_seen) { int delta = pc.time_zone * 60;#ifdef HAVE_TM_GMTOFF delta -= tm.tm_gmtoff;#else struct tm *gmt = gmtime (&Start); if (! gmt) return -1; delta -= tm_diff (&tm, gmt);#endif if ((Start < Start - delta) != (delta < 0)) return -1; /* time_t overflow */ Start -= delta; } /* Add relative hours, minutes, and seconds. Ignore leap seconds; i.e. "+ 10 minutes" means 600 seconds, even if one of them is a leap second. Typically this is not what the user wants, but it's too hard to do it the other way, because the time zone indicator must be applied before relative times, and if mktime is applied again the time zone will be lost. */ { time_t t0 = Start; long d1 = 60 * 60 * (long) pc.rel_hour; time_t t1 = t0 + d1; long d2 = 60 * (long) pc.rel_minutes; time_t t2 = t1 + d2; int d3 = pc.rel_seconds; time_t t3 = t2 + d3; if ((d1 / (60 * 60) ^ pc.rel_hour) | (d2 / 60 ^ pc.rel_minutes) | ((t0 + d1 < t0) ^ (d1 < 0)) | ((t1 + d2 < t1) ^ (d2 < 0)) | ((t2 + d3 < t2) ^ (d3 < 0))) return -1; Start = t3; } return Start;}#if TEST#include <stdio.h>intmain (int ac, char **av){ char buff[BUFSIZ]; time_t d; printf ("Enter date, or blank line to exit.\n\t> "); fflush (stdout); buff[BUFSIZ - 1] = 0; while (fgets (buff, BUFSIZ - 1, stdin) && buff[0]) { d = get_date (buff, 0); if (d == (time_t) -1) printf ("Bad format - couldn't convert.\n"); else printf ("%s", ctime (&d)); printf ("\t> "); fflush (stdout); } return 0;}#endif /* defined TEST */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -