Datum ora_timestamp_round(PG_FUNCTION_ARGS) { Timestamp timestamp = PG_GETARG_TIMESTAMP(0); Timestamp result; text *fmt = PG_GETARG_TEXT_PP(1); fsec_t fsec; struct pg_tm tt, *tm = &tt; bool redotz = false; if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMPTZ(timestamp); if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); tm_round(tm, fmt, &redotz); if (tm2timestamp(tm, fsec, NULL, &result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); PG_RETURN_TIMESTAMP(result); }
Datum ora_timestamptz_round(PG_FUNCTION_ARGS) { TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); TimestampTz result; text *fmt = PG_GETARG_TEXT_PP(1); int tz; fsec_t fsec; struct pg_tm tt, *tm = &tt; const char *tzn; bool redotz = false; if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMPTZ(timestamp); if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); tm_round(tm, fmt, &redotz); if (redotz) tz = DetermineTimeZoneOffset(tm, get_session_timezone(fcinfo)); if (tm2timestamp(tm, fsec, &tz, &result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); PG_RETURN_TIMESTAMPTZ(result); }
void PGTYPEStimestamp_current(timestamp * ts) { struct tm tm; GetCurrentDateTime(&tm); tm2timestamp(&tm, 0, NULL, ts); return; }
static timestamp SetEpochTimestamp(void) { timestamp dt; struct tm tt, *tm = &tt; GetEpochTime(tm); tm2timestamp(tm, 0, NULL, &dt); return dt; } /* SetEpochTimestamp() */
int PGTYPEStimestamp_add_interval(timestamp * tin, interval * span, timestamp * tout) { if (TIMESTAMP_NOT_FINITE(*tin)) *tout = *tin; else { if (span->month != 0) { struct tm tt, *tm = &tt; fsec_t fsec; if (timestamp2tm(*tin, NULL, tm, &fsec, NULL) != 0) return -1; tm->tm_mon += span->month; if (tm->tm_mon > MONTHS_PER_YEAR) { tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR; tm->tm_mon = (tm->tm_mon - 1) % MONTHS_PER_YEAR + 1; } else if (tm->tm_mon < 1) { tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1; tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR; } /* adjust for end of month boundary problems... */ if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]); if (tm2timestamp(tm, fsec, NULL, tin) != 0) return -1; } *tin += span->time; *tout = *tin; } return 0; }
/** * Convert ASN1_TIME object to PostgreSQL timestamp. */ int asn1Time_to_timestamp(ASN1_TIME *asn1, Timestamp *dt) { BIO *bio; char buf[DATE_LEN]; struct tm tm; struct pg_tm pgtm; int r; // extract 'not before' date bio = BIO_new(BIO_s_mem()); if ((r = ASN1_TIME_print(bio, asn1)) <= 0) { BIO_free(bio); ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("unable to retrieve timestamp"))); return 1; } // convert 'not before' date if ((r = BIO_gets(bio, buf, DATE_LEN)) <= 0) { BIO_free(bio); ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("unable to create ISO-8601 timestamp"))); return 1; } BIO_free(bio); memset(&tm, 0, sizeof(struct tm)); strptime(buf, "%b %d %T %Y %z", &tm); pgtm.tm_sec = tm.tm_sec; pgtm.tm_min = tm.tm_min; pgtm.tm_hour = tm.tm_hour; pgtm.tm_mday= tm.tm_mday; pgtm.tm_mon= tm.tm_mon + 1; pgtm.tm_year = tm.tm_year + 1900; pgtm.tm_wday= tm.tm_wday; pgtm.tm_yday = tm.tm_yday; pgtm.tm_isdst = tm.tm_isdst; pgtm.tm_gmtoff = 0; pgtm.tm_zone = "UTC"; tm2timestamp(&pgtm, 0, NULL, dt); return 0; }
static timestamp SetEpochTimestamp(void) { #ifdef HAVE_INT64_TIMESTAMP int64 noresult = 0; #else double noresult = 0.0; #endif timestamp dt; struct tm tt, *tm = &tt; if (GetEpochTime(tm) < 0) return noresult; tm2timestamp(tm, 0, NULL, &dt); return dt; } /* SetEpochTimestamp() */
/* abstime_timestamptz() * Convert abstime to timestamp with time zone. */ Datum abstime_timestamptz(PG_FUNCTION_ARGS) { AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0); TimestampTz result; struct pg_tm tt, *tm = &tt; int tz; char zone[MAXDATELEN + 1], *tzn = zone; switch (abstime) { case INVALID_ABSTIME: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert abstime \"invalid\" to timestamp"), errOmitLocation(true))); TIMESTAMP_NOBEGIN(result); break; case NOSTART_ABSTIME: TIMESTAMP_NOBEGIN(result); break; case NOEND_ABSTIME: TIMESTAMP_NOEND(result); break; default: abstime2tm(abstime, &tz, tm, &tzn); if (tm2timestamp(tm, 0, &tz, &result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"), errOmitLocation(true))); break; }; PG_RETURN_TIMESTAMP(result); }
timestamp PGTYPEStimestamp_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, &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; }
/* timestamptz_pl_interval() * Add a interval to a timestamp with time zone data type. * Note that interval has provisions for qualitative year/month * units, so try to do the right thing with them. * To add a month, increment the month, and use the same day of month. * Then, if the next month has fewer days, set the day of month * to the last day of month. * Lastly, add in the "quantitative time". */ TimestampTz timestamptz_pl_interval(TimestampTz timestamp, Interval *span) { TimestampTz result; int tz; if (TIMESTAMP_NOT_FINITE(timestamp)) result = timestamp; else { if (span->month != 0) { struct tm tt, *tm = &tt; fsec_t fsec; if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) warnx("timestamp out of range"); tm->tm_mon += span->month; if (tm->tm_mon > MONTHS_PER_YEAR) { tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR; tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1; } else if (tm->tm_mon < 1) { tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1; tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR; } /* adjust for end of month boundary problems... */ if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]); tz = DetermineTimeZoneOffset(tm, session_timezone); if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0) warnx("timestamp out of range"); } if (span->day != 0) { struct tm tt, *tm = &tt; fsec_t fsec; int julian; if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) warnx("timestamp out of range"); /* Add days by converting to and from julian */ julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day; j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); tz = DetermineTimeZoneOffset(tm, session_timezone); if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0) warnx("timestamp out of range"); } timestamp += span->time; result = timestamp; } return result; }