📄 timestamp.c
字号:
#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() */static 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; *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 * * 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 tz; 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, &tz, 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) { case 'a': replace_val.str_val = pgtypes_date_weekdays_short[dow]; replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case 'A': replace_val.str_val = days[dow]; replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case 'b': case 'h': replace_val.str_val = months[tm->tm_mon]; replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case 'B': replace_val.str_val = pgtypes_date_months[tm->tm_mon]; replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case 'c': /* XXX */ break; case 'C': replace_val.uint_val = tm->tm_year / 100; replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case 'd': replace_val.uint_val = tm->tm_mday; replace_type = PGTYPES_TYPE_UINT_2_LZ; break; 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; case 'e': replace_val.uint_val = tm->tm_mday; replace_type = PGTYPES_TYPE_UINT_2_LS; break; case 'E':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -