📄 interval.c
字号:
#include "postgres_fe.h"#include <time.h>#include <math.h>#ifdef __FAST_MATH__#error -ffast-math is known to break this code#endif#include "extern.h"#include "dt.h"#include "pgtypes_error.h"#include "pgtypes_interval.h"/* TrimTrailingZeros() * ... resulting from printing numbers with full precision. */static voidTrimTrailingZeros(char *str){ int len = strlen(str); /* chop off trailing zeros... but leave at least 2 fractional digits */ while (*(str + len - 1) == '0' && *(str + len - 3) != '.') { len--; *(str + len) = '\0'; }}/* 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() *//* DecodeInterval() * Interpret previously parsed fields for general time interval. * Return 0 if decoded and -1 if problems. * * Allow "date" field DTK_DATE since this could be just * an unsigned floating point number. - thomas 1997-11-16 * * Allow ISO-style time span, with implicit units on number of days * preceding an hh:mm:ss field. - thomas 1998-04-30 */intDecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fsec_t *fsec){ int is_before = FALSE; char *cp; int fmask = 0, tmask, type; int i; int val; double fval; *dtype = DTK_DELTA; type = IGNORE_DTF; tm->tm_year = 0; tm->tm_mon = 0; tm->tm_mday = 0; tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; *fsec = 0; /* read through list backwards to pick up units before values */ for (i = nf - 1; i >= 0; i--) { switch (ftype[i]) { case DTK_TIME: if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) return -1; type = DTK_DAY; break; case DTK_TZ: /* * Timezone is a token with a leading sign character and * otherwise the same as a non-signed time field */ /* * A single signed number ends up here, but will be rejected * by DecodeTime(). So, work this out to drop through to * DTK_NUMBER, which *can* tolerate this. */ cp = field[i] + 1; while (*cp != '\0' && *cp != ':' && *cp != '.') cp++; if (*cp == ':' && DecodeTime((field[i] + 1), fmask, &tmask, tm, fsec) == 0) { if (*field[i] == '-') { /* flip the sign on all fields */ tm->tm_hour = -tm->tm_hour; tm->tm_min = -tm->tm_min; tm->tm_sec = -tm->tm_sec; *fsec = -(*fsec); } /* * Set the next type to be a day, if units are not * specified. This handles the case of '1 +02:03' since we * are reading right to left. */ type = DTK_DAY; tmask = DTK_M(TZ); break; } else if (type == IGNORE_DTF) { if (*cp == '.') { /* * Got a decimal point? Then assume some sort of * seconds specification */ type = DTK_SECOND; } else if (*cp == '\0') { /* * Only a signed integer? Then must assume a * timezone-like usage */ type = DTK_HOUR; } } /* DROP THROUGH */ case DTK_DATE: case DTK_NUMBER: val = strtol(field[i], &cp, 10); if (type == IGNORE_DTF) type = DTK_SECOND; if (*cp == '.') { fval = strtod(cp, &cp); if (*cp != '\0') return -1; if (val < 0) fval = -fval; } else if (*cp == '\0') fval = 0; else return -1; tmask = 0; /* DTK_M(type); */ switch (type) { case DTK_MICROSEC:#ifdef HAVE_INT64_TIMESTAMP *fsec += val + fval;#else *fsec += (val + fval) * 1e-6;#endif break; case DTK_MILLISEC:#ifdef HAVE_INT64_TIMESTAMP *fsec += (val + fval) * 1000;#else *fsec += (val + fval) * 1e-3;#endif break; case DTK_SECOND: tm->tm_sec += val;#ifdef HAVE_INT64_TIMESTAMP *fsec += fval * 1000000;#else *fsec += fval;#endif tmask = DTK_M(SECOND); break; case DTK_MINUTE: tm->tm_min += val; if (fval != 0) { int sec; fval *= SECS_PER_MINUTE; sec = fval; tm->tm_sec += sec;#ifdef HAVE_INT64_TIMESTAMP *fsec += ((fval - sec) * 1000000);#else *fsec += fval - sec;#endif } tmask = DTK_M(MINUTE); break; case DTK_HOUR: tm->tm_hour += val; if (fval != 0) { int sec; fval *= SECS_PER_HOUR; sec = fval; tm->tm_sec += sec;#ifdef HAVE_INT64_TIMESTAMP *fsec += (fval - sec) * 1000000;#else *fsec += fval - sec;#endif } tmask = DTK_M(HOUR); break; case DTK_DAY: tm->tm_mday += val; if (fval != 0) { int sec; fval *= SECS_PER_DAY; sec = fval; tm->tm_sec += sec;#ifdef HAVE_INT64_TIMESTAMP *fsec += (fval - sec) * 1000000;#else *fsec += fval - sec;#endif } tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY); break; case DTK_WEEK: tm->tm_mday += val * 7; if (fval != 0) { int sec; fval *= 7 * SECS_PER_DAY; sec = fval; tm->tm_sec += sec;#ifdef HAVE_INT64_TIMESTAMP *fsec += (fval - sec) * 1000000;#else *fsec += fval - sec;#endif } tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY); break; case DTK_MONTH: tm->tm_mon += val; if (fval != 0) { int sec; fval *= DAYS_PER_MONTH * SECS_PER_DAY; sec = fval; tm->tm_sec += sec;#ifdef HAVE_INT64_TIMESTAMP *fsec += (fval - sec) * 1000000;#else *fsec += fval - sec;#endif } tmask = DTK_M(MONTH); break; case DTK_YEAR: tm->tm_year += val; if (fval != 0) tm->tm_mon += fval * MONTHS_PER_YEAR; tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR); break; case DTK_DECADE: tm->tm_year += val * 10; if (fval != 0) tm->tm_mon += fval * MONTHS_PER_YEAR * 10; tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR); break; case DTK_CENTURY: tm->tm_year += val * 100; if (fval != 0) tm->tm_mon += fval * MONTHS_PER_YEAR * 100; tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR); break; case DTK_MILLENNIUM: tm->tm_year += val * 1000; if (fval != 0) tm->tm_mon += fval * MONTHS_PER_YEAR * 1000; tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR); break; default: return -1; } break; case DTK_STRING: case DTK_SPECIAL: type = DecodeUnits(i, field[i], &val); if (type == IGNORE_DTF) continue; tmask = 0; /* DTK_M(type); */ switch (type) { case UNITS: type = val; break; case AGO: is_before = TRUE; type = val; break; case RESERV: tmask = (DTK_DATE_M || DTK_TIME_M); *dtype = val; break; default: return -1; } break; default: return -1; } if (tmask & fmask) return -1; fmask |= tmask; } if (*fsec != 0) { int sec;#ifdef HAVE_INT64_TIMESTAMP sec = *fsec / USECS_PER_SEC;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -