📄 datetime.c
字号:
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 } 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); 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; ftype[i] = 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? */ if (cp != NULL) { /* * Under limited circumstances, we will accept a * date... */ if (i == 0 && nf >= 2 && ftype[nf - 1] == DTK_DATE) { dterr = DecodeDate(field[i], fmask, &tmask, tm); if (dterr) return dterr; } /* embedded decimal and several digits before? */ else if (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 | DTK_DATE_M), &tmask, tm, fsec, &is2digits); if (dterr < 0) return dterr; ftype[i] = dterr; } else return DTERR_BAD_FORMAT; } else if (flen > 4) { dterr = DecodeNumberField(flen, field[i], (fmask | DTK_DATE_M), &tmask, tm, fsec, &is2digits); if (dterr < 0) return dterr; ftype[i] = dterr; } /* otherwise it is a single date/time field... */ else { dterr = DecodeNumber(flen, field[i], FALSE, (fmask | DTK_DATE_M), &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: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("date/time value \"current\" is no longer supported"))); return DTERR_BAD_FORMAT; break; case DTK_NOW: tmask = DTK_TIME_M; *dtype = DTK_TIME; GetCurrentTimeUsec(tm, fsec, NULL); break; case DTK_ZULU: tmask = (DTK_TIME_M | DTK_M(TZ)); *dtype = DTK_TIME; tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; tm->tm_isdst = 0; break; default: return DTERR_BAD_FORMAT; } break; case DTZMOD: /* * daylight savings time modifier (solves "MET DST" * syntax) */ tmask |= DTK_M(DTZ); tm->tm_isdst = 1; if (tzp == NULL) return DTERR_BAD_FORMAT; *tzp += val * MINS_PER_HOUR; break; case DTZ: /* * set mask for TZ here _or_ check for DTZ later when * getting default timezone */ tmask |= DTK_M(TZ); tm->tm_isdst = 1; if (tzp == NULL) return DTERR_BAD_FORMAT; *tzp = val * MINS_PER_HOUR; ftype[i] = DTK_TZ; break; case TZ: tm->tm_isdst = 0; if (tzp == NULL) return DTERR_BAD_FORMAT; *tzp = val * MINS_PER_HOUR; ftype[i] = DTK_TZ; break; case IGNORE_DTF: break; case AMPM: mer = val; break; case UNITS: tmask = 0; ptype = val; break; case ISOTIME: tmask = 0; /*** * We will need one of the following fields: * DTK_NUMBER should be hhmmss.fff * DTK_TIME should be hh:mm:ss.fff * DTK_DATE should be hhmmss-zz ***/ if (i >= nf - 1 || (ftype[i + 1] != DTK_NUMBER && ftype[i + 1] != DTK_TIME && ftype[i + 1] != DTK_DATE)) return DTERR_BAD_FORMAT; ptype = val; break; default: return DTERR_BAD_FORMAT; } break; default: return DTERR_BAD_FORMAT; } if (tmask & fmask) return DTERR_BAD_FORMAT; fmask |= tmask; } if (mer != HR24 && tm->tm_hour > 12) return DTERR_FIELD_OVERFLOW; if (mer == AM && tm->tm_hour == 12) tm->tm_hour = 0; else if (mer == PM && tm->tm_hour != 12) tm->tm_hour += 12; if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 || tm->tm_sec < 0 || tm->tm_sec > 60 || tm->tm_hour > 24 || /* test for > 24:00:00 */ (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0 ||#ifdef HAVE_INT64_TIMESTAMP *fsec > INT64CONST(0))) || *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC) return DTERR_FIELD_OVERFLOW;#else *fsec > 0)) || *fsec < 0 || *fsec >= 1) return DTERR_FIELD_OVERFLOW;#endif if ((fmask & DTK_TIME_M) != DTK_TIME_M) return DTERR_BAD_FORMAT; /* timezone not specified? then find local timezone if possible */ if (tzp != NULL && !(fmask & DTK_M(TZ))) { struct pg_tm tt, *tmp = &tt; /* * daylight savings time modifier but no standard timezone? then error */ if (fmask & DTK_M(DTZMOD)) return DTERR_BAD_FORMAT; if ((fmask & DTK_DATE_M) == 0) GetCurrentDateTime(tmp); else { tmp->tm_year = tm->tm_year; tmp->tm_mon = tm->tm_mon; tmp->tm_mday = tm->tm_mday; } tmp->tm_hour = tm->tm_hour; tmp->tm_min = tm->tm_min; tmp->tm_sec = tm->tm_sec; *tzp = DetermineTimeZoneOffset(tmp, global_timezone); tm->tm_isdst = tmp->tm_isdst; } return 0;}/* DecodeDate() * Decode date string which includes delimiters. * Return 0 if okay, a DTERR code if not. * * Insist on a complete set of fields. */static intDecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm){ fsec_t fsec; int nf = 0; int i, len; int dterr; bool haveTextMonth = FALSE; int bc = FALSE; int is2digits = FALSE; int type, val, dmask = 0; char *field[MAXDATEFIELDS]; /* parse this string... */ while (*str != '\0' && nf < MAXDATEFIELDS) { /* skip field separators */ while (!isalnum((unsigned char) *str)) str++; field[nf] = str; if (isdigit((unsigned char) *str)) { while (isdigit((unsigned char) *str)) 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 DTERR_BAD_FORMAT;#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; haveTextMonth = TRUE; break; case ADBC: bc = (val == BC); break; default: return DTERR_BAD_FORMAT; } if (fmask & dmask) return DTERR_BAD_FORMAT; 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 DTERR_BAD_FORMAT; dterr = DecodeNumber(len, field[i], haveTextMonth, fmask, &dmask, tm, &fsec, &is2digits); if (dterr) return dterr; if (fmask & dmask) return DTERR_BAD_FORMAT; fmask |= dmask; *tmask |= dmask; } if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M) return DTERR_BAD_FORMAT; /* 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 (tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR) return DTERR_MD_FIELD_OVERFLOW; /* check for valid day */ if (tm->tm_mday < 1 || tm->tm_mday > 31) return DTERR_MD_FIELD_OVERFLOW; /* We don't want to hint about DateStyle for Feb 29 */ 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 = strtol(str, &cp, 10); if (errno == ERANGE) return DTERR_FIELD_OVERFLOW; if (*cp != ':') return DTERR_BAD_FORMAT; str = cp + 1; errno = 0; tm->tm_min = strtol(str, &c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -