📄 interval.c
字号:
/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/interval.c,v 1.37 2007/08/22 08:20:58 meskes Exp $ */#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"/* 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 extra_days; fval *= 7; extra_days = (int32) fval; tm->tm_mday += extra_days; fval -= extra_days; 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_MONTH: tm->tm_mon += val; if (fval != 0) { int day; fval *= DAYS_PER_MONTH; day = fval; tm->tm_mday += day; fval -= day; 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 = 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; *fsec -= sec * USECS_PER_SEC;#else TMODULO(*fsec, sec, 1.0);#endif tm->tm_sec += sec; } if (is_before) { *fsec = -(*fsec); tm->tm_sec = -(tm->tm_sec); tm->tm_min = -(tm->tm_min); tm->tm_hour = -(tm->tm_hour); tm->tm_mday = -(tm->tm_mday); tm->tm_mon = -(tm->tm_mon); tm->tm_year = -(tm->tm_year); } /* ensure that at least one time field has been found */ return (fmask != 0) ? 0 : -1;} /* DecodeInterval() *//* EncodeInterval() * Interpret time structure as a delta time and convert to string. * * Support "traditional Postgres" and ISO-8601 styles. * Actually, afaik ISO does not address time interval formatting, * but this looks similar to the spec for absolute date/time. * - thomas 1998-04-30 */intEncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str){ int is_before = FALSE; int is_nonzero = FALSE; char *cp = str; /* * The sign of year and month are guaranteed to match, since they are * stored internally as "month". But we'll need to check for is_before and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -