datetime.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,681 行 · 第 1/5 页
C
2,681 行
} else { ftype[nf] = DTK_DATE; while (isalnum((unsigned char) *cp) || *cp == delim) APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++)); } } /* * 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 (*cp == '.') { APPEND_CHAR(bufp, bufend, *cp++); while (isdigit((unsigned char) *cp)) APPEND_CHAR(bufp, bufend, *cp++); ftype[nf] = DTK_NUMBER; } /* * text? then date string, month, day of week, special, or timezone */ else if (isalpha((unsigned char) *cp)) { bool is_date; ftype[nf] = DTK_STRING; APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++)); while (isalpha((unsigned char) *cp)) APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++)); /* * Dates can have embedded '-', '/', or '.' separators. It could * also be a timezone name containing embedded '/', '+', '-', '_', * or ':' (but '_' or ':' can't be the first punctuation). If the * next character is a digit or '+', we need to check whether what * we have so far is a recognized non-timezone keyword --- if so, * don't believe that this is the start of a timezone. */ is_date = false; if (*cp == '-' || *cp == '/' || *cp == '.') is_date = true; else if (*cp == '+' || isdigit((unsigned char) *cp)) { *bufp = '\0'; /* null-terminate current field value */ /* we need search only the core token table, not TZ names */ if (datebsearch(field[nf], datetktbl, szdatetktbl) == NULL) is_date = true; } if (is_date) { ftype[nf] = DTK_DATE; do { APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++)); } while (*cp == '+' || *cp == '-' || *cp == '/' || *cp == '_' || *cp == '.' || *cp == ':' || isalnum((unsigned char) *cp)); } } /* sign? then special or numeric timezone */ else if (*cp == '+' || *cp == '-') { APPEND_CHAR(bufp, bufend, *cp++); /* soak up leading whitespace */ while (isspace((unsigned char) *cp)) cp++; /* numeric timezone? */ if (isdigit((unsigned char) *cp)) { ftype[nf] = DTK_TZ; APPEND_CHAR(bufp, bufend, *cp++); while (isdigit((unsigned char) *cp) || *cp == ':' || *cp == '.') APPEND_CHAR(bufp, bufend, *cp++); } /* special? */ else if (isalpha((unsigned char) *cp)) { ftype[nf] = DTK_SPECIAL; APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++)); while (isalpha((unsigned char) *cp)) APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++)); } /* otherwise something wrong... */ else return DTERR_BAD_FORMAT; } /* ignore other punctuation but use as delimiter */ else if (ispunct((unsigned char) *cp)) { cp++; continue; } /* otherwise, something is not right... */ else return DTERR_BAD_FORMAT; /* force in a delimiter after each field */ *bufp++ = '\0'; nf++; } *numfields = nf; return 0;}/* DecodeDateTime() * Interpret previously parsed fields for general date and time. * Return 0 if full date, 1 if only time, and negative DTERR code if problems. * (Currently, all callers treat 1 as an error return too.) * * 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 pg_tm * tm, fsec_t *fsec, int *tzp){ int fmask = 0, tmask, type; int ptype = 0; /* "prefix type" for ISO y2001m02d04 format */ int i; int val; int dterr; int mer = HR24; bool haveTextMonth = FALSE; bool is2digits = FALSE; bool bc = FALSE; pg_tz *namedTz = NULL; /* * 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 DTERR_BAD_FORMAT; errno = 0; val = strtoi(field[i], &cp, 10); if (errno == ERANGE) return DTERR_FIELD_OVERFLOW; j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); /* Get the time zone from the end of the string */ dterr = DecodeTimezone(cp, tzp); if (dterr) return dterr; tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ); ptype = 0; break; } /*** * Already have a date? Then this might be a time zone name * with embedded punctuation (e.g. "America/New_York") or a * run-together time with trailing time zone (e.g. hhmmss-zz). * - thomas 2001-12-25 * * We consider it a time zone if we already have month & day. * This is to allow the form "mmm dd hhmmss tz year", which * we've historically accepted. ***/ else if (ptype != 0 || ((fmask & (DTK_M(MONTH) | DTK_M(DAY))) == (DTK_M(MONTH) | DTK_M(DAY)))) { /* No time zone accepted? Then quit... */ if (tzp == NULL) return DTERR_BAD_FORMAT; if (isdigit((unsigned char) *field[i]) || ptype != 0) { char *cp; if (ptype != 0) { /* Sanity check; should not fail this test */ if (ptype != DTK_TIME) return DTERR_BAD_FORMAT; ptype = 0; } /* * Starts with a digit but we already have a time * field? Then we are in trouble with a date and time * already... */ if ((fmask & DTK_TIME_M) == DTK_TIME_M) return DTERR_BAD_FORMAT; if ((cp = strchr(field[i], '-')) == NULL) return DTERR_BAD_FORMAT; /* Get the time zone from the end of the string */ dterr = DecodeTimezone(cp, tzp); if (dterr) return dterr; *cp = '\0'; /* * Then read the rest of the field as a concatenated * time */ dterr = DecodeNumberField(strlen(field[i]), field[i], fmask, &tmask, tm, fsec, &is2digits); if (dterr < 0) return dterr; /* * modify tmask after returning from * DecodeNumberField() */ tmask |= DTK_M(TZ); } else { namedTz = pg_tzset(field[i]); if (!namedTz) { /* * We should return an error code instead of * ereport'ing directly, but then there is no way * to report the bad time zone name. */ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("time zone \"%s\" not recognized", field[i]))); } /* we'll apply the zone setting below */ tmask = DTK_M(TZ); } } else { dterr = DecodeDate(field[i], fmask, &tmask, &is2digits, tm); if (dterr) return dterr; } break; case DTK_TIME: dterr = DecodeTime(field[i], fmask, &tmask, tm, fsec); if (dterr) return dterr; /* * Check upper limit on hours; other limits checked in * DecodeTime() */ /* test for > 24:00:00 */ if (tm->tm_hour > 24 || (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0))) return DTERR_FIELD_OVERFLOW; break; case DTK_TZ: { int tz; if (tzp == NULL) return DTERR_BAD_FORMAT; dterr = DecodeTimezone(field[i], &tz); if (dterr) return dterr; *tzp = tz; tmask = DTK_M(TZ); } break; case DTK_NUMBER: /* * Was this an "ISO date" with embedded field labels? An * example is "y2001m02d04" - thomas 2001-02-04 */ if (ptype != 0) { char *cp; int val; errno = 0; val = strtoi(field[i], &cp, 10); if (errno == ERANGE) return DTERR_FIELD_OVERFLOW; /* * only a few kinds are allowed to have an embedded * decimal */ if (*cp == '.') switch (ptype) { case DTK_JULIAN: case DTK_TIME: case DTK_SECOND: break; default: return DTERR_BAD_FORMAT; break; } else if (*cp != '\0') return DTERR_BAD_FORMAT; switch (ptype) { case DTK_YEAR: tm->tm_year = val; tmask = DTK_M(YEAR); break; case DTK_MONTH: /* * already have a month and hour? then assume * minutes */ if ((fmask & DTK_M(MONTH)) != 0 && (fmask & DTK_M(HOUR)) != 0) { tm->tm_min = val; tmask = DTK_M(MINUTE); } else { tm->tm_mon = val; tmask = DTK_M(MONTH); } break; case DTK_DAY: tm->tm_mday = val; tmask = DTK_M(DAY); break; case DTK_HOUR: tm->tm_hour = val; tmask = DTK_M(HOUR); break; case DTK_MINUTE: tm->tm_min = val; tmask = DTK_M(MINUTE); break; case DTK_SECOND: tm->tm_sec = val; tmask = DTK_M(SECOND); if (*cp == '.') { double frac; frac = strtod(cp, &cp); if (*cp != '\0') return DTERR_BAD_FORMAT;#ifdef HAVE_INT64_TIMESTAMP *fsec = rint(frac * 1000000);#else *fsec = frac;#endif tmask = DTK_ALL_SECS_M; } break; case DTK_TZ: tmask = DTK_M(TZ); dterr = DecodeTimezone(field[i], tzp); if (dterr) return dterr; break; case DTK_JULIAN: /*** * previous field was a label for "julian date"? ***/ tmask = DTK_DATE_M; j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); /* fractional Julian Day? */ if (*cp == '.') { double time; time = strtod(cp, &cp); if (*cp != '\0') return DTERR_BAD_FORMAT; tmask |= DTK_TIME_M;#ifdef HAVE_INT64_TIMESTAMP dt2time(time * USECS_PER_DAY, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);#else dt2time(time * SECS_PER_DAY, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);#endif } break; case DTK_TIME: /* previous field was "t" for ISO time */ dterr = DecodeNumberField(strlen(field[i]), field[i], (fmask | DTK_DATE_M), &tmask, tm, fsec, &is2digits); if (dterr < 0) return dterr; if (tmask != DTK_TIME_M) return DTERR_BAD_FORMAT; break; default: return DTERR_BAD_FORMAT; break; } ptype = 0; *dtype = DTK_DATE; } else { char *cp; int flen; flen = strlen(field[i]); cp = strchr(field[i], '.'); /* Embedded decimal and no date yet? */ if (cp != NULL && !(fmask & DTK_DATE_M)) { dterr = DecodeDate(field[i], fmask, &tmask, &is2digits, tm); if (dterr) return dterr; } /* embedded decimal and several digits before? */ else if (cp != NULL && flen - strlen(cp) > 2) { /* * Interpret as a concatenated date or time Set the * type field to allow decoding other fields later. * Example: 20011223 or 040506 */ dterr = DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits); if (dterr < 0) return dterr; } else if (flen > 4) { dterr = DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits); if (dterr < 0) return dterr; } /* otherwise it is a single date/time field... */ else { dterr = DecodeNumber(flen, field[i], haveTextMonth, fmask, &tmask, tm, fsec, &is2digits); if (dterr) return dterr; } } break; case DTK_STRING: case DTK_SPECIAL: type = DecodeSpecial(i, field[i], &val); if (type == IGNORE_DTF) continue; tmask = DTK_M(type); switch (type) { case RESERV: switch (val) { case DTK_CURRENT:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?