📄 dt_common.c
字号:
str++; } else if (isalpha((unsigned char) *str)) { while (isalpha((unsigned char) *str)) str++; } /* Just get rid of any non-digit, non-alpha characters... */ if (*str != '\0') *str++ = '\0'; nf++; }#if 0 /* don't allow too many fields */ if (nf > 3) return -1;#endif *tmask = 0; /* look first for text fields, since that will be unambiguous month */ for (i = 0; i < nf; i++) { if (isalpha((unsigned char) *field[i])) { type = DecodeSpecial(i, field[i], &val); if (type == IGNORE_DTF) continue; dmask = DTK_M(type); switch (type) { case MONTH: tm->tm_mon = val; break; case ADBC: bc = (val == BC); break; default: return -1; } if (fmask & dmask) return -1; fmask |= dmask; *tmask |= dmask; /* mark this field as being completed */ field[i] = NULL; } } /* now pick up remaining numeric fields */ for (i = 0; i < nf; i++) { if (field[i] == NULL) continue; if ((len = strlen(field[i])) <= 0) return -1; if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits, EuroDates) != 0) return -1; if (fmask & dmask) return -1; fmask |= dmask; *tmask |= dmask; } if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M) return -1; /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */ if (bc) { if (tm->tm_year > 0) tm->tm_year = -(tm->tm_year - 1); else return -1; } else if (is2digits) { if (tm->tm_year < 70) tm->tm_year += 2000; else if (tm->tm_year < 100) tm->tm_year += 1900; } return 0;} /* DecodeDate() *//* DecodeTime() * Decode time string which includes delimiters. * Only check the lower limit on hours, since this same code * can be used to represent time spans. */static intDecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec){ char *cp; *tmask = DTK_TIME_M; tm->tm_hour = strtol(str, &cp, 10); if (*cp != ':') return -1; str = cp + 1; tm->tm_min = strtol(str, &cp, 10); if (*cp == '\0') { tm->tm_sec = 0; *fsec = 0; } else if (*cp != ':') return -1; else { str = cp + 1; tm->tm_sec = strtol(str, &cp, 10); if (*cp == '\0') *fsec = 0; else if (*cp == '.') {#ifdef HAVE_INT64_TIMESTAMP char fstr[MAXDATELEN + 1]; /* * OK, we have at most six digits to work with. Let's construct a * string and then do the conversion to an integer. */ strncpy(fstr, (cp + 1), 7); strcpy(fstr + strlen(fstr), "000000"); *(fstr + 6) = '\0'; *fsec = strtol(fstr, &cp, 10);#else str = cp; *fsec = strtod(str, &cp);#endif if (*cp != '\0') return -1; } else return -1; } /* do a sanity check */#ifdef HAVE_INT64_TIMESTAMP if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 || tm->tm_sec < 0 || tm->tm_sec > 59 || *fsec >= USECS_PER_SEC) return -1;#else if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 || tm->tm_sec < 0 || tm->tm_sec > 59 || *fsec >= 1) return -1;#endif return 0;} /* DecodeTime() *//* DecodeTimezone() * Interpret string as a numeric timezone. * * Note: we allow timezone offsets up to 13:59. There are places that * use +1300 summer time. */static intDecodeTimezone(char *str, int *tzp){ int tz; int hr, min; char *cp; int len; /* assume leading character is "+" or "-" */ hr = strtol(str + 1, &cp, 10); /* explicit delimiter? */ if (*cp == ':') min = strtol(cp + 1, &cp, 10); /* otherwise, might have run things together... */ else if (*cp == '\0' && (len = strlen(str)) > 3) { min = strtol(str + len - 2, &cp, 10); if (min < 0 || min >= 60) return -1; *(str + len - 2) = '\0'; hr = strtol(str + 1, &cp, 10); if (hr < 0 || hr > 13) return -1; } else min = 0; tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE; if (*str == '-') tz = -tz; *tzp = -tz; return *cp != '\0';} /* DecodeTimezone() *//* DecodePosixTimezone() * Interpret string as a POSIX-compatible timezone: * PST-hh:mm * PST+h * - thomas 2000-03-15 */static intDecodePosixTimezone(char *str, int *tzp){ int val, tz; int type; char *cp; char delim; cp = str; while (*cp != '\0' && isalpha((unsigned char) *cp)) cp++; if (DecodeTimezone(cp, &tz) != 0) return -1; delim = *cp; *cp = '\0'; type = DecodeSpecial(MAXDATEFIELDS - 1, str, &val); *cp = delim; switch (type) { case DTZ: case TZ: *tzp = (val * MINS_PER_HOUR) - tz; break; default: return -1; } return 0;} /* DecodePosixTimezone() *//* ParseDateTime() * Break string into tokens based on a date/time context. * Several field types are assigned: * DTK_NUMBER - digits and (possibly) a decimal point * DTK_DATE - digits and two delimiters, or digits and text * DTK_TIME - digits, colon delimiters, and possibly a decimal point * DTK_STRING - text (no digits) * DTK_SPECIAL - leading "+" or "-" followed by text * DTK_TZ - leading "+" or "-" followed by digits * Note that some field types can hold unexpected items: * DTK_NUMBER can hold date fields (yy.ddd) * DTK_STRING can hold months (January) and time zones (PST) * DTK_DATE can hold Posix time zones (GMT-8) */intParseDateTime(char *timestr, char *lowstr, char **field, int *ftype, int maxfields, int *numfields, char **endstr){ int nf = 0; char *lp = lowstr; *endstr = timestr; /* outer loop through fields */ while (*(*endstr) != '\0') { field[nf] = lp; /* leading digit? then date or time */ if (isdigit((unsigned char) *(*endstr))) { *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr))) *lp++ = *(*endstr)++; /* time field? */ if (*(*endstr) == ':') { ftype[nf] = DTK_TIME; *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr)) || (*(*endstr) == ':') || (*(*endstr) == '.')) *lp++ = *(*endstr)++; } /* date field? allow embedded text month */ else if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.') { /* save delimiting character to use later */ char *dp = (*endstr); *lp++ = *(*endstr)++; /* second field is all digits? then no embedded text month */ if (isdigit((unsigned char) *(*endstr))) { ftype[nf] = (*dp == '.') ? DTK_NUMBER : DTK_DATE; while (isdigit((unsigned char) *(*endstr))) *lp++ = *(*endstr)++; /* * insist that the delimiters match to get a three-field * date. */ if (*(*endstr) == *dp) { ftype[nf] = DTK_DATE; *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr)) || (*(*endstr) == *dp)) *lp++ = *(*endstr)++; } } else { ftype[nf] = DTK_DATE; while (isalnum((unsigned char) *(*endstr)) || (*(*endstr) == *dp)) *lp++ = pg_tolower((unsigned char) *(*endstr)++); } } /* * otherwise, number only and will determine year, month, day, or * concatenated fields later... */ else ftype[nf] = DTK_NUMBER; } /* Leading decimal point? Then fractional seconds... */ else if (*(*endstr) == '.') { *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr))) *lp++ = *(*endstr)++; ftype[nf] = DTK_NUMBER; } /* * text? then date string, month, day of week, special, or timezone */ else if (isalpha((unsigned char) *(*endstr))) { ftype[nf] = DTK_STRING; *lp++ = pg_tolower((unsigned char) *(*endstr)++); while (isalpha((unsigned char) *(*endstr))) *lp++ = pg_tolower((unsigned char) *(*endstr)++); /* * Full date string with leading text month? Could also be a POSIX * time zone... */ if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.') { char *dp = (*endstr); ftype[nf] = DTK_DATE; *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr)) || *(*endstr) == *dp) *lp++ = *(*endstr)++; } } /* skip leading spaces */ else if (isspace((unsigned char) *(*endstr))) { (*endstr)++; continue; } /* sign? then special or numeric timezone */ else if (*(*endstr) == '+' || *(*endstr) == '-') { *lp++ = *(*endstr)++; /* soak up leading whitespace */ while (isspace((unsigned char) *(*endstr))) (*endstr)++; /* numeric timezone? */ if (isdigit((unsigned char) *(*endstr))) { ftype[nf] = DTK_TZ; *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr)) || (*(*endstr) == ':') || (*(*endstr) == '.')) *lp++ = *(*endstr)++; } /* special? */ else if (isalpha((unsigned char) *(*endstr))) { ftype[nf] = DTK_SPECIAL; *lp++ = pg_tolower((unsigned char) *(*endstr)++); while (isalpha((unsigned char) *(*endstr))) *lp++ = pg_tolower((unsigned char) *(*endstr)++); } /* otherwise something wrong... */ else return -1; } /* ignore punctuation but use as delimiter */ else if (ispunct((unsigned char) *(*endstr))) { (*endstr)++; continue; } /* otherwise, something is not right... */ else return -1; /* force in a delimiter after each field */ *lp++ = '\0'; nf++; if (nf > MAXDATEFIELDS) return -1; } *numfields = nf; return 0;} /* ParseDateTime() *//* DecodeDateTime() * Interpret previously parsed fields for general date and time. * Return 0 if full date, 1 if only time, and -1 if problems. * External format(s): * "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>" * "Fri Feb-7-1997 15:23:27" * "Feb-7-1997 15:23:27" * "2-7-1997 15:23:27" * "1997-2-7 15:23:27" * "1997.038 15:23:27" (day of year 1-366) * Also supports input in compact time: * "970207 152327" * "97038 152327" * "20011225T040506.789-07" * * Use the system-provided functions to get the current time zone * if not specified in the input string. * If the date is outside the time_t system-supported time range, * then assume UTC time zone. - thomas 1997-05-27 */intDecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fsec_t *fsec, int *tzp, bool EuroDates){ int fmask = 0, tmask, type; int ptype = 0; /* "prefix type" for ISO y2001m02d04 format */ int i; int val; int mer = HR24; int haveTextMonth = FALSE; int is2digits = FALSE; int bc = FALSE; /*** * We'll insist on at least all of the date fields, but initialize the * remaining fields in case they are not set later... ***/ *dtype = DTK_DATE; tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; *fsec = 0; /* don't know daylight savings time status apriori */ tm->tm_isdst = -1; if (tzp != NULL) *tzp = 0; for (i = 0; i < nf; i++) { switch (ftype[i]) { case DTK_DATE: /*** * Integral julian day with attached time zone? * All other forms with JD will be separated into * distinct fields, so we handle just this case here. ***/ if (ptype == DTK_JULIAN) { char *cp; int val; if (tzp == NULL) return -1; val = strtol(field[i], &cp, 10); if (*cp != '-') return -1; j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); /* Get the time zone from the end of the string */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -