* Functions for the built-in type "RelativeTime".
* Functions for the built-in type "TimeInterval".
*
- * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.149 2007/01/05 22:19:41 momjian Exp $
+ * src/backend/utils/adt/nabstime.c
*
*-------------------------------------------------------------------------
*/
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "utils/builtins.h"
+#include "utils/datetime.h"
#include "utils/nabstime.h"
#define MIN_DAYNUM (-24856) /* December 13, 1901 */
#define MAX_DAYNUM 24854 /* January 18, 2038 */
-#define INVALID_RELTIME_STR "Undefined RelTime"
-#define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
-#define RELTIME_LABEL '@'
-#define RELTIME_PAST "ago"
-#define DIRMAXLEN (sizeof(RELTIME_PAST)-1)
-
/*
* Unix epoch is Jan 1 00:00:00 1970.
* Postgres knows about times sixty-eight years on either side of that
* GetCurrentAbsoluteTime()
*
* Get the current system time (relative to Unix epoch).
+ *
+ * NB: this will overflow in 2038; it should be gone long before that.
*/
AbsoluteTime
GetCurrentAbsoluteTime(void)
pg_time_t time = (pg_time_t) _time;
struct pg_tm *tx;
- /*
- * 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 (HasCTZSet && (tzp != NULL))
- time -= CTimeZone;
-
- if (!HasCTZSet && tzp != NULL)
- tx = pg_localtime(&time, global_timezone);
+ if (tzp != NULL)
+ tx = pg_localtime(&time, session_timezone);
else
tx = pg_gmtime(&time);
if (tzp != NULL)
{
- /*
- * We have a brute force time zone per SQL99? Then use it without
- * change since we have already rotated to the time zone.
- */
- if (HasCTZSet)
- {
- *tzp = CTimeZone;
- tm->tm_gmtoff = CTimeZone;
- tm->tm_isdst = 0;
- tm->tm_zone = NULL;
- if (tzn != NULL)
- *tzn = NULL;
- }
- else
- {
*tzp = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
/*
errmsg("invalid time zone name: \"%s\"",
tm->tm_zone)));
}
- }
}
else
tm->tm_isdst = -1;
/* validate, before going out of range on some members */
if (tm->tm_year < 1901 || tm->tm_year > 2038 ||
- tm->tm_mon < 1 || tm->tm_mon > 12 ||
+ tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR ||
tm->tm_mday < 1 || tm->tm_mday > 31 ||
tm->tm_hour < 0 ||
- tm->tm_hour > 24 || /* test for > 24:00:00 */
- (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0)) ||
- tm->tm_min < 0 || tm->tm_min > 59 ||
- tm->tm_sec < 0 || tm->tm_sec > 60)
+ tm->tm_hour > HOURS_PER_DAY || /* test for > 24:00:00 */
+ (tm->tm_hour == HOURS_PER_DAY && (tm->tm_min > 0 || tm->tm_sec > 0)) ||
+ tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
+ tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE)
return INVALID_ABSTIME;
day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
break;
default:
abstime2tm(time, &tz, tm, &tzn);
- EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
+ EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
break;
}
result = NOEND_ABSTIME;
else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
{
- tz = DetermineTimeZoneOffset(tm, global_timezone);
+ tz = DetermineTimeZoneOffset(tm, session_timezone);
result = tm2abstime(tm, tz);
}
else
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
field, ftype, MAXDATEFIELDS, &nf);
if (dterr == 0)
- dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
+ dterr = DecodeInterval(field, ftype, nf, INTERVAL_FULL_RANGE,
+ &dtype, tm, &fsec);
+
+ /* if those functions think it's a bad format, try ISO8601 style */
+ if (dterr == DTERR_BAD_FORMAT)
+ dterr = DecodeISO8601Interval(str,
+ &dtype, tm, &fsec);
+
if (dterr != 0)
{
if (dterr == DTERR_FIELD_OVERFLOW)
char buf[MAXDATELEN + 1];
reltime2tm(time, tm);
- EncodeInterval(tm, 0, DateStyle, buf);
+ EncodeInterval(tm, 0, IntervalStyle, buf);
result = pstrdup(buf);
PG_RETURN_CSTRING(result);
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
TimeInterval tinterval;
+ int32 status;
tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
tinterval->status = pq_getmsgint(buf, sizeof(tinterval->status));
+ tinterval->data[0] = pq_getmsgint(buf, sizeof(tinterval->data[0]));
+ tinterval->data[1] = pq_getmsgint(buf, sizeof(tinterval->data[1]));
+
+ if (tinterval->data[0] == INVALID_ABSTIME ||
+ tinterval->data[1] == INVALID_ABSTIME)
+ status = T_INTERVAL_INVAL; /* undefined */
+ else
+ status = T_INTERVAL_VALID;
- if (!(tinterval->status == T_INTERVAL_INVAL ||
- tinterval->status == T_INTERVAL_VALID))
+ if (status != tinterval->status)
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid status in external \"tinterval\" value")));
- tinterval->data[0] = pq_getmsgint(buf, sizeof(tinterval->data[0]));
- tinterval->data[1] = pq_getmsgint(buf, sizeof(tinterval->data[1]));
-
PG_RETURN_TIMEINTERVAL(tinterval);
}
int year,
month,
day;
-
-#ifdef HAVE_INT64_TIMESTAMP
- int64 span;
-#else
- double span;
-#endif
+ TimeOffset span;
year = interval->month / MONTHS_PER_YEAR;
month = interval->month % MONTHS_PER_YEAR;
Datum
timenow(PG_FUNCTION_ARGS)
{
- time_t sec;
-
- if (time(&sec) < 0)
- PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
-
- PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
+ PG_RETURN_ABSOLUTETIME(GetCurrentAbsoluteTime());
}
/*
/*
* tinterval comparison routines
*
- * Note: comparison is based on the lengths of the tintervals, not on
- * endpoint value. This is pretty bogus, but since it's only a legacy
- * datatype I'm not going to propose changing it.
+ * Note: comparison is based only on the lengths of the tintervals, not on
+ * endpoint values (as long as they're not INVALID). This is pretty bogus,
+ * but since it's only a legacy datatype, we're not going to change it.
+ *
+ * Some other bogus things that won't be changed for compatibility reasons:
+ * 1. The interval length computations overflow at 2^31 seconds, causing
+ * intervals longer than that to sort oddly compared to those shorter.
+ * 2. infinity and minus infinity (NOEND_ABSTIME and NOSTART_ABSTIME) are
+ * just ordinary integers. Since this code doesn't handle them specially,
+ * it's possible for [a b] to be considered longer than [c infinity] for
+ * finite abstimes a, b, c. In combination with the previous point, the
+ * interval [-infinity infinity] is treated as being shorter than many finite
+ * intervals :-(
+ *
+ * If tinterval is ever reimplemented atop timestamp, it'd be good to give
+ * some consideration to avoiding these problems.
*/
static int
tinterval_cmp_internal(TimeInterval a, TimeInterval b)
struct timeval tp;
char templ[128];
char buf[128];
- text *result;
- int len;
pg_time_t tt;
gettimeofday(&tp, NULL);
tt = (pg_time_t) tp.tv_sec;
pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
- pg_localtime(&tt, global_timezone));
+ pg_localtime(&tt, session_timezone));
snprintf(buf, sizeof(buf), templ, tp.tv_usec);
- len = VARHDRSZ + strlen(buf);
- result = (text *) palloc(len);
- VARATT_SIZEP(result) = len;
- memcpy(VARDATA(result), buf, strlen(buf));
- PG_RETURN_TEXT_P(result);
+ PG_RETURN_TEXT_P(cstring_to_text(buf));
}