📄 timestamp.c
字号:
pq_begintypsend(&buf);#ifdef HAVE_INT64_TIMESTAMP pq_sendint64(&buf, interval->time);#else pq_sendfloat8(&buf, interval->time);#endif pq_sendint(&buf, interval->month, sizeof(interval->month)); PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/* interval_scale() * Adjust interval type for specified fields. * Used by PostgreSQL type system to stuff columns. */Datuminterval_scale(PG_FUNCTION_ARGS){ Interval *interval = PG_GETARG_INTERVAL_P(0); int32 typmod = PG_GETARG_INT32(1); Interval *result; result = palloc(sizeof(Interval)); *result = *interval; AdjustIntervalForTypmod(result, typmod); PG_RETURN_INTERVAL_P(result);}static voidAdjustIntervalForTypmod(Interval *interval, int32 typmod){#ifdef HAVE_INT64_TIMESTAMP static const int64 IntervalScales[MAX_INTERVAL_PRECISION + 1] = { INT64CONST(1000000), INT64CONST(100000), INT64CONST(10000), INT64CONST(1000), INT64CONST(100), INT64CONST(10), INT64CONST(1) }; static const int64 IntervalOffsets[MAX_INTERVAL_PRECISION + 1] = { INT64CONST(500000), INT64CONST(50000), INT64CONST(5000), INT64CONST(500), INT64CONST(50), INT64CONST(5), INT64CONST(0) };#else static const double IntervalScales[MAX_INTERVAL_PRECISION + 1] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };#endif /* * Unspecified range and precision? Then not necessary to adjust. * Setting typmod to -1 is the convention for all types. */ if (typmod != -1) { int range = INTERVAL_RANGE(typmod); int precision = INTERVAL_PRECISION(typmod); if (range == INTERVAL_FULL_RANGE) { /* Do nothing... */ } else if (range == INTERVAL_MASK(YEAR)) { interval->month = ((interval->month / 12) * 12); interval->time = 0; } else if (range == INTERVAL_MASK(MONTH)) { interval->month %= 12; interval->time = 0; } /* YEAR TO MONTH */ else if (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH))) interval->time = 0; else if (range == INTERVAL_MASK(DAY)) { interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP interval->time = (((int) (interval->time / INT64CONST(86400000000))) * INT64CONST(86400000000));#else interval->time = (((int) (interval->time / 86400)) * 86400);#endif } else if (range == INTERVAL_MASK(HOUR)) {#ifdef HAVE_INT64_TIMESTAMP int64 day;#else double day;#endif interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP day = (interval->time / INT64CONST(86400000000)); interval->time -= (day * INT64CONST(86400000000)); interval->time = ((interval->time / INT64CONST(3600000000)) * INT64CONST(3600000000));#else TMODULO(interval->time, day, 86400.0); interval->time = (((int) (interval->time / 3600)) * 3600.0);#endif } else if (range == INTERVAL_MASK(MINUTE)) {#ifdef HAVE_INT64_TIMESTAMP int64 hour;#else double hour;#endif interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP hour = (interval->time / INT64CONST(3600000000)); interval->time -= (hour * INT64CONST(3600000000)); interval->time = ((interval->time / INT64CONST(60000000)) * INT64CONST(60000000));#else TMODULO(interval->time, hour, 3600.0); interval->time = (((int) (interval->time / 60)) * 60);#endif } else if (range == INTERVAL_MASK(SECOND)) {#ifdef HAVE_INT64_TIMESTAMP int64 minute;#else double minute;#endif interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP minute = (interval->time / INT64CONST(60000000)); interval->time -= (minute * INT64CONST(60000000));#else TMODULO(interval->time, minute, 60.0);/* interval->time = (int)(interval->time); */#endif } /* DAY TO HOUR */ else if (range == (INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR))) { interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP interval->time = ((interval->time / INT64CONST(3600000000)) * INT64CONST(3600000000));#else interval->time = (((int) (interval->time / 3600)) * 3600);#endif } /* DAY TO MINUTE */ else if (range == (INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) { interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP interval->time = ((interval->time / INT64CONST(60000000)) * INT64CONST(60000000));#else interval->time = (((int) (interval->time / 60)) * 60);#endif } /* DAY TO SECOND */ else if (range == (INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND))) interval->month = 0; /* HOUR TO MINUTE */ else if (range == (INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) {#ifdef HAVE_INT64_TIMESTAMP int64 day;#else double day;#endif interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP day = (interval->time / INT64CONST(86400000000)); interval->time -= (day * INT64CONST(86400000000)); interval->time = ((interval->time / INT64CONST(60000000)) * INT64CONST(60000000));#else TMODULO(interval->time, day, 86400.0); interval->time = (((int) (interval->time / 60)) * 60);#endif } /* HOUR TO SECOND */ else if (range == (INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND))) {#ifdef HAVE_INT64_TIMESTAMP int64 day;#else double day;#endif interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP day = (interval->time / INT64CONST(86400000000)); interval->time -= (day * INT64CONST(86400000000));#else TMODULO(interval->time, day, 86400.0);#endif } /* MINUTE TO SECOND */ else if (range == (INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND))) {#ifdef HAVE_INT64_TIMESTAMP int64 hour;#else double hour;#endif interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP hour = (interval->time / INT64CONST(3600000000)); interval->time -= (hour * INT64CONST(3600000000));#else TMODULO(interval->time, hour, 3600.0);#endif } else elog(ERROR, "unrecognized interval typmod: %d", typmod); /* Need to adjust precision? If not, don't even try! */ if (precision != INTERVAL_FULL_PRECISION) { if ((precision < 0) || (precision > MAX_INTERVAL_PRECISION)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("interval(%d) precision must be between %d and %d", precision, 0, MAX_INTERVAL_PRECISION))); /* * Note: this round-to-nearest code is not completely * consistent about rounding values that are exactly halfway * between integral values. On most platforms, rint() will * implement round-to-nearest-even, but the integer code * always rounds up (away from zero). Is it worth trying to * be consistent? */#ifdef HAVE_INT64_TIMESTAMP if (interval->time >= INT64CONST(0)) { interval->time = (((interval->time + IntervalOffsets[precision]) / IntervalScales[precision]) * IntervalScales[precision]); } else { interval->time = -(((-interval->time + IntervalOffsets[precision]) / IntervalScales[precision]) * IntervalScales[precision]); }#else interval->time = (rint(((double) interval->time) * IntervalScales[precision]) / IntervalScales[precision]);#endif } } return;}/* EncodeSpecialTimestamp() * Convert reserved timestamp data type to string. */static intEncodeSpecialTimestamp(Timestamp dt, char *str){ if (TIMESTAMP_IS_NOBEGIN(dt)) strcpy(str, EARLY); else if (TIMESTAMP_IS_NOEND(dt)) strcpy(str, LATE); else return FALSE; return TRUE;} /* EncodeSpecialTimestamp() */Datumnow(PG_FUNCTION_ARGS){ TimestampTz result; AbsoluteTime sec; int usec; sec = GetCurrentTransactionStartTimeUsec(&usec); result = AbsoluteTimeUsecToTimestampTz(sec, usec); PG_RETURN_TIMESTAMPTZ(result);}voiddt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec){#ifdef HAVE_INT64_TIMESTAMP int64 time;#else double time;#endif time = jd;#ifdef HAVE_INT64_TIMESTAMP *hour = (time / INT64CONST(3600000000)); time -= ((*hour) * INT64CONST(3600000000)); *min = (time / INT64CONST(60000000)); time -= ((*min) * INT64CONST(60000000)); *sec = (time / INT64CONST(1000000)); *fsec = (time - (*sec * INT64CONST(1000000)));#else *hour = (time / 3600); time -= ((*hour) * 3600); *min = (time / 60); time -= ((*min) * 60); *sec = time; *fsec = JROUND(time - *sec);#endif return;} /* dt2time() *//* timestamp2tm() * Convert timestamp data type to POSIX time structure. * Note that year is _not_ 1900-based, but is an explicit full value. * Also, month is one-based, _not_ zero-based. * Returns: * 0 on success * -1 on out of range * * For dates within the system-supported time_t range, convert to the * local time zone. If out of this range, leave as GMT. - tgl 97/05/27 */inttimestamp2tm(Timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, char **tzn){#ifdef HAVE_INT64_TIMESTAMP int date; int64 time;#else double date; double time;#endif time_t utime;#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE) struct tm *tx;#endif /* * If HasCTZSet is true then we have a brute force time zone * specified. Go ahead and rotate to the local time zone since we will * later bypass any calls which adjust the tm fields. */ if (HasCTZSet && (tzp != NULL)) {#ifdef HAVE_INT64_TIMESTAMP dt -= (CTimeZone * INT64CONST(1000000));#else dt -= CTimeZone;#endif } time = dt;#ifdef HAVE_INT64_TIMESTAMP TMODULO(time, date, INT64CONST(86400000000)); if (time < INT64CONST(0)) { time += INT64CONST(86400000000); date -= 1; }#else TMODULO(time, date, 86400e0); if (time < 0) { time += 86400; date -= 1; }#endif /* Julian day routine does not work for negative Julian days */ if (date < -POSTGRES_EPOCH_JDATE) return -1; /* add offset to go from J2000 back to standard Julian date */ date += POSTGRES_EPOCH_JDATE; j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); if (tzp != NULL) { /* * We have a brute force time zone per SQL99? Then use it without * change since we have already rotated to the time zone. */ if (HasCTZSet) { *tzp = CTimeZone; tm->tm_isdst = 0;#if defined(HAVE_TM_ZONE) tm->tm_gmtoff = CTimeZone; tm->tm_zone = NULL;#endif if (tzn != NULL) *tzn = NULL; } /* * Does this fall within the capabilities of the localtime() * interface? Then use this to rotate to the local time zone. */ else if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) { /* * Convert to integer, avoiding platform-specific * roundoff-in-wrong-direction errors, and adjust to * Unix epoch. Note we have to do this in one step * because the intermediate result before adjustment * won't necessarily fit in an int32. */#ifdef HAVE_INT64_TIMESTAMP utime = (dt - *fsec) / INT64CONST(1000000) + (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400;#else utime = rint(dt - *fsec + (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400);#endif#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE) tx = localtime(&utime); tm->tm_year = tx->tm_year + 1900; tm->tm_mon = tx->tm_mon + 1; tm->tm_mday = tx->tm_mday; tm->tm_hour = tx->tm_hour; tm->tm_min = tx->tm_min;#if NOT_USED/* XXX HACK * Argh! My Linux box puts in a 1 second offset for dates less than 1970 * but only if the seconds field was non-zero. So, don't copy the seconds * field and instead carry forward from the original - thomas 97/06/18 * Note that Linux uses the standard freeware zic package as do * many other platforms so this may not be Linux/ix86-specific. * Still shows a problem on my up to date Linux box - thomas 2001-01-17 */ tm->tm_sec = tx->tm_sec;#endif tm->tm_isdst = tx->tm_isdst;#if defined(HAVE_TM_ZONE) tm->tm_gmtoff = tx->tm_gmtoff; tm->tm_zone = tx->tm_zone; *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */ if (tzn != NULL) *tzn = (char *) tm->tm_zone;#elif defined(HAVE_INT_TIMEZONE) *tzp = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL); if (tzn != NULL) *tzn = tzname[(tm->tm_isdst > 0)];#endif#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */ *tzp = 0; /* Mark this as *no* time zone available */ tm->tm_isdst = -1; if (tzn != NULL) *tzn = NULL;#endif } else { *tzp = 0; /* Mark this as *no* time zone available */ tm->tm_isdst = -1; if (tzn != NULL) *tzn = NULL; } } else { tm->tm_isdst = -1; if (tzn != NULL) *tzn = NULL; } return 0;}/* tm2timestamp() * Convert a tm structure to a timestamp data type. * Note that year is _not_ 1900-based, but is an explicit full value. * Also, month is one-based, _not_ zero-based. * * Returns -1 on failure (value out of range). */inttm2timestamp(struct tm * tm, fsec_t fsec, int *tzp, Timestamp *result){#ifdef HAVE_INT64_TIMESTAMP int date; int64 time;#else double date, time;#endif /* Julian day routines are not correct for negative Julian days */ if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday)) return -1; date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE; time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);#ifdef HAVE_INT64_TIMESTAMP *result = (date * INT64CONST(86400000000)) + time; /* check for major overflow */ if ((*result - time) / INT64CONST(86400000000) != date) return -1; /* check for just-barely overflow (okay except time-of-day wraps) */ if ((*result < 0) ? (date >= 0) : (date < 0)) return -1;#else *result = ((date * 86400) + time);#endif if (tzp != NULL) *result = dt2local(*result, -(*tzp)); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -