📄 timestamp.c
字号:
}/* interval_out() * Convert a time span to external form. */Datuminterval_out(PG_FUNCTION_ARGS){ Interval *span = PG_GETARG_INTERVAL_P(0); char *result; struct pg_tm tt, *tm = &tt; fsec_t fsec; char buf[MAXDATELEN + 1]; if (interval2tm(*span, tm, &fsec) != 0) elog(ERROR, "could not convert interval to tm"); if (EncodeInterval(tm, fsec, DateStyle, buf) != 0) elog(ERROR, "could not format interval"); result = pstrdup(buf); PG_RETURN_CSTRING(result);}/* * interval_recv - converts external binary format to interval */Datuminterval_recv(PG_FUNCTION_ARGS){ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);#ifdef NOT_USED Oid typelem = PG_GETARG_OID(1);#endif int32 typmod = PG_GETARG_INT32(2); Interval *interval; interval = (Interval *) palloc(sizeof(Interval));#ifdef HAVE_INT64_TIMESTAMP interval->time = pq_getmsgint64(buf);#else interval->time = pq_getmsgfloat8(buf);#endif interval->day = pq_getmsgint(buf, sizeof(interval->day)); interval->month = pq_getmsgint(buf, sizeof(interval->month)); AdjustIntervalForTypmod(interval, typmod); PG_RETURN_INTERVAL_P(interval);}/* * interval_send - converts interval to binary format */Datuminterval_send(PG_FUNCTION_ARGS){ Interval *interval = PG_GETARG_INTERVAL_P(0); StringInfoData buf; pq_begintypsend(&buf);#ifdef HAVE_INT64_TIMESTAMP pq_sendint64(&buf, interval->time);#else pq_sendfloat8(&buf, interval->time);#endif pq_sendint(&buf, interval->day, sizeof(interval->day)); 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);}/* * Adjust interval for specified precision, in both YEAR to SECOND * range and sub-second precision. */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 / MONTHS_PER_YEAR) * MONTHS_PER_YEAR; interval->day = 0; interval->time = 0; } else if (range == INTERVAL_MASK(MONTH)) { interval->month %= MONTHS_PER_YEAR; interval->day = 0; interval->time = 0; } /* YEAR TO MONTH */ else if (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH))) { /* month is already year to month */ interval->day = 0; interval->time = 0; } else if (range == INTERVAL_MASK(DAY)) { interval->month = 0; interval->time = 0; } else if (range == INTERVAL_MASK(HOUR)) { interval->month = 0; interval->day = 0;#ifdef HAVE_INT64_TIMESTAMP interval->time = (interval->time / USECS_PER_HOUR) * USECS_PER_HOUR;#else interval->time = ((int) (interval->time / SECS_PER_HOUR)) * (double) SECS_PER_HOUR;#endif } else if (range == INTERVAL_MASK(MINUTE)) {#ifdef HAVE_INT64_TIMESTAMP int64 hour;#else double hour;#endif interval->month = 0; interval->day = 0;#ifdef HAVE_INT64_TIMESTAMP hour = interval->time / USECS_PER_HOUR; interval->time -= hour * USECS_PER_HOUR; interval->time = (interval->time / USECS_PER_MINUTE) * USECS_PER_MINUTE;#else TMODULO(interval->time, hour, (double) SECS_PER_HOUR); interval->time = ((int) (interval->time / SECS_PER_MINUTE)) * (double) SECS_PER_MINUTE;#endif } else if (range == INTERVAL_MASK(SECOND)) {#ifdef HAVE_INT64_TIMESTAMP int64 minute;#else double minute;#endif interval->month = 0; interval->day = 0;#ifdef HAVE_INT64_TIMESTAMP minute = interval->time / USECS_PER_MINUTE; interval->time -= minute * USECS_PER_MINUTE;#else TMODULO(interval->time, minute, (double) SECS_PER_MINUTE); /* return subseconds too */#endif } /* DAY TO HOUR */ else if (range == (INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR))) { interval->month = 0;#ifdef HAVE_INT64_TIMESTAMP interval->time = (interval->time / USECS_PER_HOUR) * USECS_PER_HOUR;#else interval->time = ((int) (interval->time / SECS_PER_HOUR)) * (double) SECS_PER_HOUR;#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 / USECS_PER_MINUTE) * USECS_PER_MINUTE;#else interval->time = ((int) (interval->time / SECS_PER_MINUTE)) * (double) SECS_PER_MINUTE;#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))) { interval->month = 0; interval->day = 0;#ifdef HAVE_INT64_TIMESTAMP interval->time = (interval->time / USECS_PER_MINUTE) * USECS_PER_MINUTE;#else interval->time = ((int) (interval->time / SECS_PER_MINUTE)) * (double) SECS_PER_MINUTE;#endif } /* HOUR TO SECOND */ else if (range == (INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND))) { interval->month = 0; interval->day = 0; /* return subseconds too */ } /* 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; interval->day = 0;#ifdef HAVE_INT64_TIMESTAMP hour = interval->time / USECS_PER_HOUR; interval->time -= hour * USECS_PER_HOUR;#else TMODULO(interval->time, hour, (double) SECS_PER_HOUR);#endif } else elog(ERROR, "unrecognized interval typmod: %d", typmod); /* Need to adjust subsecond precision? */ 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){ PG_RETURN_TIMESTAMPTZ(GetCurrentTransactionStartTimestamp());}Datumpgsql_postmaster_start_time(PG_FUNCTION_ARGS){ PG_RETURN_TIMESTAMPTZ(PgStartTime);}/* * GetCurrentTimestamp -- get the current operating system time * * Result is in the form of a TimestampTz value, and is expressed to the * full precision of the gettimeofday() syscall */TimestampTzGetCurrentTimestamp(void){ TimestampTz result; struct timeval tp; gettimeofday(&tp, NULL); result = (TimestampTz) tp.tv_sec - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);#ifdef HAVE_INT64_TIMESTAMP result = (result * USECS_PER_SEC) + tp.tv_usec;#else result = result + (tp.tv_usec / 1000000.0);#endif return result;}/* * Convert a time_t to TimestampTz. * * We do not use time_t internally in Postgres, but this is provided for use * by functions that need to interpret, say, a stat(2) result. */TimestampTztime_t_to_timestamptz(time_t tm){ TimestampTz result; result = (TimestampTz) tm - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);#ifdef HAVE_INT64_TIMESTAMP result *= USECS_PER_SEC;#endif return 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 / USECS_PER_HOUR; time -= (*hour) * USECS_PER_HOUR; *min = time / USECS_PER_MINUTE; time -= (*min) * USECS_PER_MINUTE; *sec = time / USECS_PER_SEC; *fsec = time - (*sec * USECS_PER_SEC);#else *hour = time / SECS_PER_HOUR; time -= (*hour) * SECS_PER_HOUR; *min = time / SECS_PER_MINUTE; time -= (*min) * SECS_PER_MINUTE; *sec = time; *fsec = time - *sec;#endif} /* 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 * * If attimezone is NULL, the global timezone (including possibly brute forced * timezone) will be used. */inttimestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn, pg_tz *attimezone){ Timestamp date; Timestamp time; pg_time_t utime; /* * 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 (attimezone == NULL && HasCTZSet && tzp != NULL) {#ifdef HAVE_INT64_TIMESTAMP dt -= CTimeZone * USECS_PER_SEC;#else dt -= CTimeZone;#endif }#ifdef HAVE_INT64_TIMESTAMP time = dt; TMODULO(time, date, USECS_PER_DAY); if (time < INT64CONST(0)) { time += USECS_PER_DAY; date -= 1; } /* add offset to go from J2000 back to standard Julian date */ date += POSTGRES_EPOCH_JDATE; /* Julian day routine does not work for negative Julian days */ if (date < 0 || date > (Timestamp) INT_MAX) return -1; j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);#else time = dt; TMODULO(time, date, (double) SECS_PER_DAY); if (time < 0) { time += SECS_PER_DAY; date -= 1; } /* add offset to go from J2000 back to standard Julian date */ date += POSTGRES_EPOCH_JDATE;recalc_d: /* Julian day routine does not work for negative Julian days */ if (date < 0 || date > (Timestamp) INT_MAX) return -1; j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);recalc_t: dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); *fsec = TSROUND(*fsec); /* roundoff may need to propagate to higher-order fields */ if (*fsec >= 1.0) { time = ceil(time); if (time >= (double) SECS_PER_DAY) { time = 0; date += 1; goto recalc_d; } goto recalc_t; }#endif /* Done if no TZ conversion wanted */ if (tzp == NULL) { tm->tm_isdst = -1; tm->tm_gmtoff = 0; tm->tm_zone = NULL; if (tzn != NULL) *tzn = NULL; return 0; } /* * We have a brute force time zone per SQL99? Then use it without change * since we have already rotated to the time zone.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -