datetime.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,681 行 · 第 1/5 页
C
2,681 行
* Return 0 if okay, a DTERR code if not. */static intValidateDate(int fmask, bool is2digits, bool bc, struct pg_tm * tm){ if (fmask & DTK_M(YEAR)) { /* 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 ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("inconsistent use of year %04d and \"BC\"", tm->tm_year))); } else if (is2digits) { if (tm->tm_year < 70) tm->tm_year += 2000; else if (tm->tm_year < 100) tm->tm_year += 1900; } } /* now that we have correct year, decode DOY */ if (fmask & DTK_M(DOY)) { j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); } /* check for valid month */ if (fmask & DTK_M(MONTH)) { if (tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR) return DTERR_MD_FIELD_OVERFLOW; } /* minimal check for valid day */ if (fmask & DTK_M(DAY)) { if (tm->tm_mday < 1 || tm->tm_mday > 31) return DTERR_MD_FIELD_OVERFLOW; } if ((fmask & DTK_DATE_M) == DTK_DATE_M) { /* * Check for valid day of month, now that we know for sure the month * and year. Note we don't use MD_FIELD_OVERFLOW here, since it seems * unlikely that "Feb 29" is a YMD-order error. */ if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) return DTERR_FIELD_OVERFLOW; } return 0;}/* DecodeTime() * Decode time string which includes delimiters. * Return 0 if okay, a DTERR code if not. * * 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 pg_tm * tm, fsec_t *fsec){ char *cp; *tmask = DTK_TIME_M; errno = 0; tm->tm_hour = strtoi(str, &cp, 10); if (errno == ERANGE) return DTERR_FIELD_OVERFLOW; if (*cp != ':') return DTERR_BAD_FORMAT; str = cp + 1; errno = 0; tm->tm_min = strtoi(str, &cp, 10); if (errno == ERANGE) return DTERR_FIELD_OVERFLOW; if (*cp == '\0') { tm->tm_sec = 0; *fsec = 0; } else if (*cp != ':') return DTERR_BAD_FORMAT; else { str = cp + 1; errno = 0; tm->tm_sec = strtoi(str, &cp, 10); if (errno == ERANGE) return DTERR_FIELD_OVERFLOW; if (*cp == '\0') *fsec = 0; else if (*cp == '.') { double frac; str = cp; frac = strtod(str, &cp); if (*cp != '\0') return DTERR_BAD_FORMAT;#ifdef HAVE_INT64_TIMESTAMP *fsec = rint(frac * 1000000);#else *fsec = frac;#endif } else return DTERR_BAD_FORMAT; } /* 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 > 60 || *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC) return DTERR_FIELD_OVERFLOW;#else if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 || tm->tm_sec < 0 || tm->tm_sec > 60 || *fsec < 0 || *fsec >= 1) return DTERR_FIELD_OVERFLOW;#endif return 0;}/* DecodeNumber() * Interpret plain numeric field as a date value in context. * Return 0 if okay, a DTERR code if not. */static intDecodeNumber(int flen, char *str, bool haveTextMonth, int fmask, int *tmask, struct pg_tm * tm, fsec_t *fsec, bool *is2digits){ int val; char *cp; int dterr; *tmask = 0; errno = 0; val = strtoi(str, &cp, 10); if (errno == ERANGE) return DTERR_FIELD_OVERFLOW; if (cp == str) return DTERR_BAD_FORMAT; if (*cp == '.') { double frac; /* * More than two digits before decimal point? Then could be a date or * a run-together time: 2001.360 20011225 040506.789 */ if (cp - str > 2) { dterr = DecodeNumberField(flen, str, (fmask | DTK_DATE_M), tmask, tm, fsec, is2digits); if (dterr < 0) return dterr; return 0; } frac = strtod(cp, &cp); if (*cp != '\0') return DTERR_BAD_FORMAT;#ifdef HAVE_INT64_TIMESTAMP *fsec = rint(frac * 1000000);#else *fsec = frac;#endif } else if (*cp != '\0') return DTERR_BAD_FORMAT; /* Special case for day of year */ if (flen == 3 && (fmask & DTK_DATE_M) == DTK_M(YEAR) && val >= 1 && val <= 366) { *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY)); tm->tm_yday = val; /* tm_mon and tm_mday can't actually be set yet ... */ return 0; } /* Switch based on what we have so far */ switch (fmask & DTK_DATE_M) { case 0: /* * Nothing so far; make a decision about what we think the input * is. There used to be lots of heuristics here, but the * consensus now is to be paranoid. It *must* be either * YYYY-MM-DD (with a more-than-two-digit year field), or the * field order defined by DateOrder. */ if (flen >= 3 || DateOrder == DATEORDER_YMD) { *tmask = DTK_M(YEAR); tm->tm_year = val; } else if (DateOrder == DATEORDER_DMY) { *tmask = DTK_M(DAY); tm->tm_mday = val; } else { *tmask = DTK_M(MONTH); tm->tm_mon = val; } break; case (DTK_M(YEAR)): /* Must be at second field of YY-MM-DD */ *tmask = DTK_M(MONTH); tm->tm_mon = val; break; case (DTK_M(MONTH)): if (haveTextMonth) { /* * We are at the first numeric field of a date that included a * textual month name. We want to support the variants * MON-DD-YYYY, DD-MON-YYYY, and YYYY-MON-DD as unambiguous * inputs. We will also accept MON-DD-YY or DD-MON-YY in * either DMY or MDY modes, as well as YY-MON-DD in YMD mode. */ if (flen >= 3 || DateOrder == DATEORDER_YMD) { *tmask = DTK_M(YEAR); tm->tm_year = val; } else { *tmask = DTK_M(DAY); tm->tm_mday = val; } } else { /* Must be at second field of MM-DD-YY */ *tmask = DTK_M(DAY); tm->tm_mday = val; } break; case (DTK_M(YEAR) | DTK_M(MONTH)): if (haveTextMonth) { /* Need to accept DD-MON-YYYY even in YMD mode */ if (flen >= 3 && *is2digits) { /* Guess that first numeric field is day was wrong */ *tmask = DTK_M(DAY); /* YEAR is already set */ tm->tm_mday = tm->tm_year; tm->tm_year = val; *is2digits = FALSE; } else { *tmask = DTK_M(DAY); tm->tm_mday = val; } } else { /* Must be at third field of YY-MM-DD */ *tmask = DTK_M(DAY); tm->tm_mday = val; } break; case (DTK_M(DAY)): /* Must be at second field of DD-MM-YY */ *tmask = DTK_M(MONTH); tm->tm_mon = val; break; case (DTK_M(MONTH) | DTK_M(DAY)): /* Must be at third field of DD-MM-YY or MM-DD-YY */ *tmask = DTK_M(YEAR); tm->tm_year = val; break; case (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)): /* we have all the date, so it must be a time field */ dterr = DecodeNumberField(flen, str, fmask, tmask, tm, fsec, is2digits); if (dterr < 0) return dterr; return 0; default: /* Anything else is bogus input */ return DTERR_BAD_FORMAT; } /* * When processing a year field, mark it for adjustment if it's only one * or two digits. */ if (*tmask == DTK_M(YEAR)) *is2digits = (flen <= 2); return 0;}/* DecodeNumberField() * Interpret numeric string as a concatenated date or time field. * Return a DTK token (>= 0) if successful, a DTERR code (< 0) if not. * * Use the context of previously decoded fields to help with * the interpretation. */static intDecodeNumberField(int len, char *str, int fmask, int *tmask, struct pg_tm * tm, fsec_t *fsec, bool *is2digits){ char *cp; /* * Have a decimal point? Then this is a date or something with a seconds * field... */ if ((cp = strchr(str, '.')) != NULL) { double frac; frac = strtod(cp, NULL);#ifdef HAVE_INT64_TIMESTAMP *fsec = rint(frac * 1000000);#else *fsec = frac;#endif *cp = '\0'; len = strlen(str); } /* No decimal point and no complete date yet? */ else if ((fmask & DTK_DATE_M) != DTK_DATE_M) { /* yyyymmdd? */ if (len == 8) { *tmask = DTK_DATE_M; tm->tm_mday = atoi(str + 6); *(str + 6) = '\0'; tm->tm_mon = atoi(str + 4); *(str + 4) = '\0'; tm->tm_year = atoi(str + 0); return DTK_DATE; } /* yymmdd? */ else if (len == 6) { *tmask = DTK_DATE_M; tm->tm_mday = atoi(str + 4); *(str + 4) = '\0'; tm->tm_mon = atoi(str + 2); *(str + 2) = '\0'; tm->tm_year = atoi(str + 0); *is2digits = TRUE; return DTK_DATE; } } /* not all time fields are specified? */ if ((fmask & DTK_TIME_M) != DTK_TIME_M) { /* hhmmss */ if (len == 6) { *tmask = DTK_TIME_M; tm->tm_sec = atoi(str + 4); *(str + 4) = '\0'; tm->tm_min = atoi(str + 2); *(str + 2) = '\0'; tm->tm_hour = atoi(str + 0); return DTK_TIME; } /* hhmm? */ else if (len == 4) { *tmask = DTK_TIME_M; tm->tm_sec = 0; tm->tm_min = atoi(str + 2); *(str + 2) = '\0'; tm->tm_hour = atoi(str + 0); return DTK_TIME; } } return DTERR_BAD_FORMAT;}/* DecodeTimezone() * Interpret string as a numeric timezone. * * Return 0 if okay (and set *tzp), a DTERR code if not okay. * * NB: this must *not* ereport on failure; see commands/variable.c. * * 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, sec = 0; char *cp; /* leading character must be "+" or "-" */ if (*str != '+' && *str != '-') return DTERR_BAD_FORMAT; errno = 0; hr = strtoi(str + 1, &cp, 10); if (errno == ERANGE) return DTERR_TZDISP_OVERFLOW; /* explicit delimiter? */ if (*cp == ':') { errno = 0; min = strtoi(cp + 1, &cp, 10); if (errno == ERANGE) return DTERR_TZDISP_OVERFLOW; if (*cp == ':') { errno = 0; sec = strtoi(cp + 1, &cp, 10); if (errno == ERANGE) return DTERR_TZDISP_OVERFLOW; } } /* otherwise, might have run things together... */ else if (*cp == '\0' && strlen(str) > 3) { min = hr % 100; hr = hr / 100; /* we could, but don't, support a run-together hhmmss format */ } else min = 0; if (hr < 0 || hr > 14) return DTERR_TZDISP_OVERFLOW; if (min < 0 || min >= 60) return DTERR_TZDISP_OVERFLOW; if (sec < 0 || sec >= 60) return DTERR_TZDISP_OVERFLOW; tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE + sec; if (*str == '-') tz = -tz; *tzp = -tz; if (*cp != '\0') return DTERR_BAD_FORMAT; return 0;}/* DecodeSpecial() * Decode text string using lookup table. * * Implement a cache lookup since it is likely that dates * will be related in format. * * NB: this must *not* ereport on failure; * see commands/variable.c. */intDecodeSpecial(int field, char *lowtoken, int *val){ int type; const datetkn *tp; tp = datecache[field]; if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0) { tp = datebsearch(lowtoken, timezonetktbl, sztimezonetktbl); if (tp == NULL) tp = datebsearch(lowtoken, datetktbl, szdatetktbl); } if (tp == NULL) { type = UNKNOWN_FIELD; *val = 0; } else { datecache[field] = tp; type = tp->type; switch (type) { case TZ: case DTZ: case DTZMOD: *val = FROMVAL(tp); break; default: *val
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?