timestamp.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,001 行 · 第 1/2 页
C
1,001 行
#include "postgres_fe.h"#include <time.h>#include <float.h>#include <limits.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_timestamp.h"#include "pgtypes_date.h"int PGTYPEStimestamp_defmt_scan(char **, char *, timestamp *, int *, int *, int *, int *, int *, int *, int *);#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() *//* 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 (overflow). */inttm2timestamp(struct tm * tm, fsec_t fsec, int *tzp, timestamp * result){#ifdef HAVE_INT64_TIMESTAMP int dDate; int64 time;#else double dDate, 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; dDate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1); time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);#ifdef HAVE_INT64_TIMESTAMP *result = (dDate * USECS_PER_DAY) + time; /* check for major overflow */ if ((*result - time) / USECS_PER_DAY != dDate) return -1; /* check for just-barely overflow (okay except time-of-day wraps) */ if ((*result < 0 && dDate >= 0) || (*result >= 0 && dDate < 0)) return -1;#else *result = dDate * SECS_PER_DAY + time;#endif if (tzp != NULL) *result = dt2local(*result, -(*tzp)); return 0;} /* tm2timestamp() */static timestampSetEpochTimestamp(void){ timestamp dt; struct tm tt, *tm = &tt; GetEpochTime(tm); tm2timestamp(tm, 0, NULL, &dt); return dt;} /* SetEpochTimestamp() *//* 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 */static inttimestamp2tm(timestamp dt, int *tzp, struct tm * tm, fsec_t *fsec, char **tzn){#ifdef HAVE_INT64_TIMESTAMP int64 dDate, date0; int64 time;#else double dDate, date0; double time;#endif time_t utime;#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE) struct tm *tx;#endif date0 = date2j(2000, 1, 1);#ifdef HAVE_INT64_TIMESTAMP time = dt; TMODULO(time, dDate, USECS_PER_DAY); if (time < INT64CONST(0)) { time += USECS_PER_DAY; dDate -= 1; } /* add offset to go from J2000 back to standard Julian date */ dDate += date0; /* Julian day routine does not work for negative Julian days */ if (dDate < 0 || dDate > (timestamp) INT_MAX) return -1; j2date((int) dDate, &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, dDate, (double) SECS_PER_DAY); if (time < 0) { time += SECS_PER_DAY; dDate -= 1; } /* add offset to go from J2000 back to standard Julian date */ dDate += date0;recalc_d: /* Julian day routine does not work for negative Julian days */ if (dDate < 0 || dDate > (timestamp) INT_MAX) return -1; j2date((int) dDate, &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; dDate += 1; goto recalc_d; } goto recalc_t; }#endif if (tzp != NULL) { /* * Does this fall within the capabilities of the localtime() * interface? Then use this to rotate to the local time zone. */ if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) {#ifdef HAVE_INT64_TIMESTAMP utime = dt / USECS_PER_SEC + ((date0 - date2j(1970, 1, 1)) * INT64CONST(86400));#else utime = dt + (date0 - date2j(1970, 1, 1)) * SECS_PER_DAY;#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; 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 - SECS_PER_HOUR : TIMEZONE_GLOBAL; if (tzn != NULL) *tzn = TZNAME_GLOBAL[(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 dt = dt2local(dt, *tzp); } 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;} /* timestamp2tm() *//* 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() */timestampPGTYPEStimestamp_from_asc(char *str, char **endptr){ timestamp result;#ifdef HAVE_INT64_TIMESTAMP int64 noresult = 0;#else double noresult = 0.0;#endif fsec_t fsec; struct tm tt, *tm = &tt; int dtype; int nf; char *field[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS]; char lowstr[MAXDATELEN + MAXDATEFIELDS]; char *realptr; char **ptr = (endptr != NULL) ? endptr : &realptr; if (strlen(str) >= sizeof(lowstr)) { errno = PGTYPES_TS_BAD_TIMESTAMP; return (noresult); } if (ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf, ptr) != 0 || DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, 0) != 0) { errno = PGTYPES_TS_BAD_TIMESTAMP; return (noresult); } switch (dtype) { case DTK_DATE: if (tm2timestamp(tm, fsec, NULL, &result) != 0) { errno = PGTYPES_TS_BAD_TIMESTAMP; return (noresult); } break; case DTK_EPOCH: result = SetEpochTimestamp(); break; case DTK_LATE: TIMESTAMP_NOEND(result); break; case DTK_EARLY: TIMESTAMP_NOBEGIN(result); break; case DTK_INVALID: errno = PGTYPES_TS_BAD_TIMESTAMP; return (noresult); default: errno = PGTYPES_TS_BAD_TIMESTAMP; return (noresult); } /* AdjustTimestampForTypmod(&result, typmod); */ /* * Since it's difficult to test for noresult, make sure errno is 0 if no * error occured. */ errno = 0; return result;}char *PGTYPEStimestamp_to_asc(timestamp tstamp){ struct tm tt, *tm = &tt; char buf[MAXDATELEN + 1]; char *tzn = NULL; fsec_t fsec; int DateStyle = 1; /* this defaults to ISO_DATES, shall we make * it an option? */ if (TIMESTAMP_NOT_FINITE(tstamp)) EncodeSpecialTimestamp(tstamp, buf); else if (timestamp2tm(tstamp, NULL, tm, &fsec, NULL) == 0) EncodeDateTime(tm, fsec, NULL, &tzn, DateStyle, buf, 0); else { errno = PGTYPES_TS_BAD_TIMESTAMP; return NULL; } return pgtypes_strdup(buf);}voidPGTYPEStimestamp_current(timestamp * ts){ struct tm tm; GetCurrentDateTime(&tm); tm2timestamp(&tm, 0, NULL, ts); return;}static intdttofmtasc_replace(timestamp * ts, date dDate, int dow, struct tm * tm, char *output, int *pstr_len, char *fmtstr){ union un_fmt_comb replace_val; int replace_type; int i; char *p = fmtstr; char *q = output; while (*p) { if (*p == '%') { p++; /* fix compiler warning */ replace_type = PGTYPES_TYPE_NOTHING; switch (*p) { /* the abbreviated name of the day in the week */ /* XXX should be locale aware */ case 'a': replace_val.str_val = pgtypes_date_weekdays_short[dow]; replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; /* the full name of the day in the week */ /* XXX should be locale aware */ case 'A': replace_val.str_val = days[dow]; replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; /* the abbreviated name of the month */ /* XXX should be locale aware */ case 'b': case 'h': replace_val.str_val = months[tm->tm_mon]; replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; /* the full name name of the month */ /* XXX should be locale aware */ case 'B': replace_val.str_val = pgtypes_date_months[tm->tm_mon]; replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; /* * The preferred date and time representation for * the current locale. */ case 'c': /* XXX */ break; /* the century number with leading zeroes */ case 'C': replace_val.uint_val = tm->tm_year / 100; replace_type = PGTYPES_TYPE_UINT_2_LZ; break; /* day with leading zeroes (01 - 31) */ case 'd': replace_val.uint_val = tm->tm_mday; replace_type = PGTYPES_TYPE_UINT_2_LZ; break; /* the date in the format mm/dd/yy */ case 'D': /* * ts, dDate, dow, tm is information about the timestamp * * q is the start of the current output buffer * * pstr_len is a pointer to the remaining size of output, * i.e. the size of q */ i = dttofmtasc_replace(ts, dDate, dow, tm, q, pstr_len, "%m/%d/%y"); if (i) return i; break; /* day with leading spaces (01 - 31) */ case 'e': replace_val.uint_val = tm->tm_mday; replace_type = PGTYPES_TYPE_UINT_2_LS; break; /* * alternative format modifier */ case 'E': { char tmp[4] = "%Ex"; p++; if (*p == '\0') return -1; tmp[2] = *p; /* * strftime's month is 0 based, ours is 1 based */ tm->tm_mon -= 1; i = strftime(q, *pstr_len, tmp, tm); if (i == 0) return -1; while (*q) { q++; (*pstr_len)--; } tm->tm_mon += 1; replace_type = PGTYPES_TYPE_NOTHING; break; } /* * The ISO 8601 year with century as a decimal number. The * 4-digit year corresponding to the ISO week number. */ case 'G': tm->tm_mon -= 1; i = strftime(q, *pstr_len, "%G", tm); if (i == 0) return -1; while (*q) { q++;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?