📄 timestamp.c
字号:
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());}Datumstatement_timestamp(PG_FUNCTION_ARGS){ PG_RETURN_TIMESTAMPTZ(GetCurrentStatementStartTimestamp());}Datumclock_timestamp(PG_FUNCTION_ARGS){ PG_RETURN_TIMESTAMPTZ(GetCurrentTimestamp());}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;}/* * TimestampDifference -- convert the difference between two timestamps * into integer seconds and microseconds * * Both inputs must be ordinary finite timestamps (in current usage, * they'll be results from GetCurrentTimestamp()). * * We expect start_time <= stop_time. If not, we return zeroes; for current * callers there is no need to be tense about which way division rounds on * negative inputs. */voidTimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs){ TimestampTz diff = stop_time - start_time; if (diff <= 0) { *secs = 0; *microsecs = 0; } else {#ifdef HAVE_INT64_TIMESTAMP *secs = (long) (diff / USECS_PER_SEC); *microsecs = (int) (diff % USECS_PER_SEC);#else *secs = (long) diff; *microsecs = (int) ((diff - *secs) * 1000000.0);#endif }}/* * TimestampDifferenceExceeds -- report whether the difference between two * timestamps is >= a threshold (expressed in milliseconds) * * Both inputs must be ordinary finite timestamps (in current usage, * they'll be results from GetCurrentTimestamp()). */boolTimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec){ TimestampTz diff = stop_time - start_time;#ifdef HAVE_INT64_TIMESTAMP return (diff >= msec * INT64CONST(1000));#else return (diff * 1000.0 >= msec);#endif}/* * 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;}/* * Convert a TimestampTz to time_t. * * This too is just marginally useful, but some places need it. */time_ttimestamptz_to_time_t(TimestampTz t){ time_t result;#ifdef HAVE_INT64_TIMESTAMP result = (time_t) (t / USECS_PER_SEC + ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));#else result = (time_t) (t + ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));#endif return result;}/* * Produce a C-string representation of a TimestampTz. * * This is mostly for use in emitting messages. The primary difference * from timestamptz_out is that we force the output format to ISO. Note * also that the result is in a static buffer, not pstrdup'd. */const char *timestamptz_to_str(TimestampTz t){ static char buf[MAXDATELEN + 1]; int tz; struct pg_tm tt, *tm = &tt; fsec_t fsec; char *tzn; if (TIMESTAMP_NOT_FINITE(t)) EncodeSpecialTimestamp(t, buf); else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0) EncodeDateTime(tm, fsec, &tz, &tzn, USE_ISO_DATES, buf); else strlcpy(buf, "(timestamp out of range)", sizeof(buf)); return buf;}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. */ if (attimezone == NULL && HasCTZSet) { *tzp = CTimeZone; tm->tm_isdst = 0; tm->tm_gmtoff = CTimeZone; tm->tm_zone = NULL; if (tzn != NULL) *tzn = NULL; return 0; } /* * If the time falls within the range of pg_time_t, use pg_localtime() to * rotate to the local time zone. * * First, convert to an integral timestamp, avoiding possibly * platform-specific roundoff-in-wrong-direction errors, and adjust to * Unix epoch. Then see if we can convert to pg_time_t without loss. This * coding avoids hardwiring any assumptions about the width of pg_time_t, * so it should behave sanely on machines without int64. */#ifdef HAVE_INT64_TIMESTAMP dt = (dt - *fsec) / USECS_PER_SEC + (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;#else dt = rint(dt - *fsec + (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);#endif utime = (pg_time_t) dt; if ((Timestamp) utime == dt) { struct pg_tm *tx = pg_localtime(&utime, attimezone ? attimezone : session_timezone); 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; tm->tm_sec = tx->tm_sec; tm->tm_isdst = tx->tm_isdst; tm->tm_gmtoff = tx->tm_gmtoff; tm->tm_zone = tx->tm_zone; *tzp = -tm->tm_gmtoff; if (tzn != NULL) *tzn = (char *) tm->tm_zone; } else { /* * When out of range of pg_time_t, treat as GMT */ *tzp = 0; /* Mark this as *no* time zone available */ tm->tm_isdst = -1; tm->tm_gmtoff = 0; tm->tm_zone = NULL; 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 pg_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)) { *result = 0; /* keep compiler quiet */ 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 * USECS_PER_DAY + time; /* check for major overflow */ if ((*result - time) / USECS_PER_DAY != date) { *result = 0; /* keep compiler quiet */ return -1; } /* check for just-barely overflow (okay except time-of-day wraps) */ if ((*result < 0 && date >= 0) || (*result >= 0 && date < 0)) { *result = 0; /* keep compiler quiet */ return -1; }#else *result = date * SECS_PER_DAY + time;#endif if (tzp != NULL) *result = dt2local(*result, -(*tzp)); return 0;}/* interval2tm() * Convert a interval data type to a tm structure. */intinterval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec){#ifdef HAVE_INT64_TIMESTAMP int64 time; int64 tfrac;#else double time; double tfrac;#endif tm->tm_year = span.month / MONTHS_PER_YEAR; tm->tm_mon = span.month % MONTHS_PER_YEAR; tm->tm_mday = span.day; time = span.time;#ifdef HAVE_INT64_TIMESTAMP tfrac = time / USECS_PER_HOUR; time -= tfrac * USECS_PER_HOUR; tm->tm_hour = tfrac; /* could overflow ... */ tfrac = time / USECS_PER_MINUTE; time -= tfrac * USECS_PER_MINUTE; tm->tm_min = tfrac; tfrac = time / USECS_PER_SEC; *fsec = time - (tfrac * USECS_PER_SEC); tm->tm_sec = tfrac;#elserecalc: TMODULO(time, tfrac, (double) SECS_PER_HOUR); tm->tm_hour = tfrac; /* could overflow ... */ TMODULO(time, tfrac, (double) SECS_PER_MINUTE); tm->tm_min = tfrac; TMODULO(time, tfrac, 1.0); tm->tm_sec = tfrac; time = TSROUND(time); /* roundoff may need to propagate to higher-order fields */ if (time >= 1.0) { time = ceil(span.time); goto recalc; } *fsec = time;#endif return 0;}inttm2interval(struct pg_tm * tm, fsec_t fsec, Interval *span){ span->month = tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon; span->day = tm->tm_mday;#ifdef HAVE_INT64_TIMESTAMP span->time = (((((tm->tm_hour * INT64CONST(60)) + tm->tm_min) * INT64CONST(60)) + tm->tm_sec) * USECS_PER_SEC) + fsec;#else span->time = (((tm->tm_hour * (double) MINS_PER_HOUR) + tm->tm_min) * (double) SECS_PER_MINUTE) + tm->tm_sec + fsec;#endif return 0;}#ifdef HAVE_INT64_TIMESTAMPstatic int64time2t(const int hour, const int min, const int sec, const fsec_t fsec){ return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;} /* time2t() */#elsestatic doubletime2t(const int hour, const int min, const int sec, const fsec_t fsec){ return (((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec + fsec;} /* time2t() */#endifstatic Timestampdt2local(Timestamp dt, int tz){#ifdef HAVE_INT64_TIMESTAMP dt -= (tz * USECS_PER_SEC);#else dt -= tz;#endif return dt;} /* dt2local() *//***************************************************************************** * PUBLIC ROUTINES * *****************************************************************************/Datumtimestamp_finite(PG_FUNCTION_ARGS){ Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -