aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/date.c510
-rw-r--r--src/backend/utils/adt/datetime.c556
-rw-r--r--src/backend/utils/adt/formatting.c21
-rw-r--r--src/backend/utils/adt/int8.c3
-rw-r--r--src/backend/utils/adt/nabstime.c96
-rw-r--r--src/backend/utils/adt/selfuncs.c19
-rw-r--r--src/backend/utils/adt/timestamp.c716
-rw-r--r--src/include/c.h6
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/catalog/pg_control.h12
-rw-r--r--src/include/catalog/pg_operator.h4
-rw-r--r--src/include/catalog/pg_proc.h27
-rw-r--r--src/include/pg_config.h.in5
-rw-r--r--src/include/utils/date.h24
-rw-r--r--src/include/utils/datetime.h35
-rw-r--r--src/include/utils/int8.h18
-rw-r--r--src/include/utils/timestamp.h69
-rw-r--r--src/test/regress/expected/horology.out47
-rw-r--r--src/test/regress/expected/timestamp.out16
-rw-r--r--src/test/regress/expected/timestamptz.out8
-rw-r--r--src/test/regress/sql/horology.sql7
21 files changed, 1653 insertions, 550 deletions
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 2c261198b45..ab8403cc318 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.65 2002/03/09 17:35:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.66 2002/04/21 19:48:12 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,10 @@
#include "utils/timestamp.h"
+int time2tm(TimeADT time, struct tm * tm, fsec_t *fsec);
+int timetz2tm(TimeTzADT *time, struct tm * tm, fsec_t *fsec, int *tzp);
+int tm2time(struct tm * tm, fsec_t fsec, TimeADT *result);
+int tm2timetz(struct tm * tm, fsec_t fsec, int tz, TimeTzADT *result);
static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
/*****************************************************************************
@@ -43,7 +47,7 @@ date_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
DateADT date;
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
int tzp;
@@ -221,6 +225,60 @@ date_mii(PG_FUNCTION_ARGS)
PG_RETURN_DATEADT(dateVal - days);
}
+#if NOT_USED
+/* date_pl_interval() and date_mi_interval() are probably
+ * better implmented by converting the input date
+ * to timestamp without time zone. So that is what we do
+ * in pg_proc.h - thomas 2002-03-11
+ */
+
+/* Add an interval to a date, giving a new date.
+ * Must handle both positive and negative intervals.
+ */
+Datum
+date_pl_interval(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ Interval *span = PG_GETARG_INTERVAL_P(1);
+ struct tm tt,
+ *tm = &tt;
+
+ if (span->month != 0)
+ {
+ j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
+ tm->tm_mon += span->month;
+ dateVal = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
+ }
+ if (span->time != 0)
+ dateVal += (span->time / 86400e0);
+
+ PG_RETURN_DATEADT(dateVal);
+}
+
+/* Subtract an interval from a date, giving a new date.
+ * Must handle both positive and negative intervals.
+ */
+Datum
+date_mi_interval(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ Interval *span = PG_GETARG_INTERVAL_P(1);
+ struct tm tt,
+ *tm = &tt;
+
+ if (span->month != 0)
+ {
+ j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
+ tm->tm_mon -= span->month;
+ dateVal = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
+ }
+ if (span->time != 0)
+ dateVal -= (span->time / 86400e0);
+
+ PG_RETURN_DATEADT(dateVal);
+}
+#endif
+
/* date_timestamp()
* Convert date to timestamp data type.
*/
@@ -230,8 +288,13 @@ date_timestamp(PG_FUNCTION_ARGS)
DateADT dateVal = PG_GETARG_DATEADT(0);
Timestamp result;
+#ifdef HAVE_INT64_TIMESTAMP
+ /* date is days since 2000, timestamp is microseconds since same... */
+ result = dateVal * INT64CONST(86400000000);
+#else
/* date is days since 2000, timestamp is seconds since same... */
result = dateVal * 86400.0;
+#endif
PG_RETURN_TIMESTAMP(result);
}
@@ -245,17 +308,23 @@ timestamp_date(PG_FUNCTION_ARGS)
{
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
DateADT result;
+#if 0
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
+#endif
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_NULL();
+#if 0
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) != 0)
elog(ERROR, "Unable to convert timestamp to date");
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
+#else
+ result = (timestamp / INT64CONST(86400000000));
+#endif
PG_RETURN_DATEADT(result);
}
@@ -289,15 +358,29 @@ date_timestamptz(PG_FUNCTION_ARGS)
if (utime == -1)
elog(ERROR, "Unable to convert date to tm");
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((utime * INT64CONST(1000000))
+ + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * INT64CONST(86400000000)));
+#else
result = utime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400.0);
+#endif
+#else
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((dateVal * INT64CONST(86400000000))
+ + (CTimeZone * INT64CONST(1000000)));
#else
result = dateVal * 86400.0 + CTimeZone;
#endif
+#endif
}
else
{
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (dateVal * INT64CONST(86400000000));
+#else
/* Outside of range for timezone support, so assume UTC */
result = dateVal * 86400.0;
+#endif
}
PG_RETURN_TIMESTAMP(result);
@@ -314,7 +397,7 @@ timestamptz_date(PG_FUNCTION_ARGS)
DateADT result;
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
int tz;
char *tzn;
@@ -427,13 +510,12 @@ Datum
time_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
-
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif
int32 typmod = PG_GETARG_INT32(2);
TimeADT result;
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
int nf;
@@ -446,13 +528,56 @@ time_in(PG_FUNCTION_ARGS)
|| (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, NULL) != 0))
elog(ERROR, "Bad time external representation '%s'", str);
- result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
-
+ tm2time(tm, fsec, &result);
AdjustTimeForTypmod(&result, typmod);
PG_RETURN_TIMEADT(result);
}
+/* tm2time()
+ * Convert a tm structure to a time data type.
+ */
+int
+tm2time(struct tm * tm, fsec_t fsec, TimeADT *result)
+{
+#ifdef HAVE_INT64_TIMESTAMP
+ *result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
+ * INT64CONST(1000000)) + fsec);
+#else
+ *result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
+#endif
+ return 0;
+}
+
+/* time2tm()
+ * Convert time data type to POSIX time structure.
+ * 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
+ */
+int
+time2tm(TimeADT time, struct tm *tm, fsec_t *fsec)
+{
+#ifdef HAVE_INT64_TIMESTAMP
+ tm->tm_hour = (time / INT64CONST(3600000000));
+ time -= (tm->tm_hour * INT64CONST(3600000000));
+ tm->tm_min = (time / INT64CONST(60000000));
+ time -= (tm->tm_min * INT64CONST(60000000));
+ tm->tm_sec = (time / INT64CONST(1000000));
+ time -= (tm->tm_sec * INT64CONST(1000000));
+ *fsec = time;
+#else
+ double trem;
+
+ trem = time;
+ TMODULO(trem, tm->tm_hour, 3600e0);
+ TMODULO(trem, tm->tm_min, 60e0);
+ TMODULO(trem, tm->tm_sec, 1e0);
+ *fsec = trem;
+#endif
+
+ return 0;
+}
+
Datum
time_out(PG_FUNCTION_ARGS)
{
@@ -460,16 +585,10 @@ time_out(PG_FUNCTION_ARGS)
char *result;
struct tm tt,
*tm = &tt;
- double fsec;
- double trem;
+ fsec_t fsec;
char buf[MAXDATELEN + 1];
- trem = time;
- TMODULO(trem, tm->tm_hour, 3600e0);
- TMODULO(trem, tm->tm_min, 60e0);
- TMODULO(trem, tm->tm_sec, 1e0);
- fsec = trem;
-
+ time2tm(time, tm, &fsec);
EncodeTimeOnly(tm, fsec, NULL, DateStyle, buf);
result = pstrdup(buf);
@@ -496,21 +615,35 @@ time_scale(PG_FUNCTION_ARGS)
static void
AdjustTimeForTypmod(TimeADT *time, int32 typmod)
{
- if ((typmod >= 0) && (typmod <= 13))
+ if ((typmod >= 0) && (typmod <= MAX_TIME_PRECISION))
{
+#ifdef HAVE_INT64_TIMESTAMP
+ static int64 TimeScale = INT64CONST(1000000);
+#else
static double TimeScale = 1;
+#endif
static int32 TimeTypmod = 0;
if (typmod != TimeTypmod)
{
+#ifdef HAVE_INT64_TIMESTAMP
+ TimeScale = pow(10.0, (MAX_TIME_PRECISION-typmod));
+#else
TimeScale = pow(10.0, typmod);
+#endif
TimeTypmod = typmod;
}
+#ifdef HAVE_INT64_TIMESTAMP
+ *time = ((*time / TimeScale) * TimeScale);
+ if (*time >= INT64CONST(86400000000))
+ *time -= INT64CONST(86400000000);
+#else
*time = (rint(((double) *time) * TimeScale) / TimeScale);
if (*time >= 86400)
*time -= 86400;
+#endif
}
return;
@@ -738,15 +871,56 @@ timestamp_time(PG_FUNCTION_ARGS)
TimeADT result;
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_NULL();
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) != 0)
- elog(ERROR, "Unable to convert timestamp to date");
+ elog(ERROR, "Unable to convert timestamp to time");
+
+#ifdef HAVE_INT64_TIMESTAMP
+ /* Could also do this with
+ * time = (timestamp / 86400000000 * 86400000000) - timestamp;
+ */
+ result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
+ * INT64CONST(1000000)) + fsec);
+#else
+ result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
+#endif
+
+ PG_RETURN_TIMEADT(result);
+}
+
+/* timestamptz_time()
+ * Convert timestamptz to time data type.
+ */
+Datum
+timestamptz_time(PG_FUNCTION_ARGS)
+{
+ TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
+ TimeADT result;
+ struct tm tt,
+ *tm = &tt;
+ int tz;
+ fsec_t fsec;
+ char *tzn;
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ PG_RETURN_NULL();
+
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
+ elog(ERROR, "Unable to convert timestamptz to time");
+
+#ifdef HAVE_INT64_TIMESTAMP
+ /* Could also do this with
+ * time = (timestamp / 86400000000 * 86400000000) - timestamp;
+ */
+ result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
+ * INT64CONST(1000000)) + fsec);
+#else
result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
+#endif
PG_RETURN_TIMEADT(result);
}
@@ -793,10 +967,18 @@ interval_time(PG_FUNCTION_ARGS)
{
Interval *span = PG_GETARG_INTERVAL_P(0);
TimeADT result;
+
+#ifdef HAVE_INT64_TIMESTAMP
+ result = span->time;
+ if ((result >= INT64CONST(86400000000))
+ || (result <= INT64CONST(-86400000000)))
+ result -= (result / INT64CONST(1000000) * INT64CONST(1000000));
+#else
Interval span1;
result = span->time;
TMODULO(result, span1.time, 86400e0);
+#endif
PG_RETURN_TIMEADT(result);
}
@@ -813,7 +995,7 @@ time_mi_time(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
- result->time = time1 - time2;
+ result->time = (time1 - time2);
result->month = 0;
PG_RETURN_INTERVAL_P(result);
@@ -828,12 +1010,20 @@ time_pl_interval(PG_FUNCTION_ARGS)
TimeADT time = PG_GETARG_TIMEADT(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
TimeADT result;
+
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (time + span->time);
+ result -= (result / INT64CONST(86400000000) * INT64CONST(86400000000));
+ if (result < INT64CONST(0))
+ result += INT64CONST(86400000000);
+#else
TimeADT time1;
result = (time + span->time);
TMODULO(result, time1, 86400e0);
if (result < 0)
result += 86400;
+#endif
PG_RETURN_TIMEADT(result);
}
@@ -847,12 +1037,20 @@ time_mi_interval(PG_FUNCTION_ARGS)
TimeADT time = PG_GETARG_TIMEADT(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
TimeADT result;
+
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (time - span->time);
+ result -= (result / INT64CONST(86400000000) * INT64CONST(86400000000));
+ if (result < INT64CONST(0))
+ result += INT64CONST(86400000000);
+#else
TimeADT time1;
result = (time - span->time);
TMODULO(result, time1, 86400e0);
if (result < 0)
result += 86400;
+#endif
PG_RETURN_TIMEADT(result);
}
@@ -926,11 +1124,137 @@ text_time(PG_FUNCTION_ARGS)
Int32GetDatum(-1));
}
+/* time_part()
+ * Extract specified field from time type.
+ */
+Datum
+time_part(PG_FUNCTION_ARGS)
+{
+ text *units = PG_GETARG_TEXT_P(0);
+ TimeADT time = PG_GETARG_TIMEADT(1);
+ float8 result;
+ int type,
+ val;
+ int i;
+ char *up,
+ *lp,
+ lowunits[MAXDATELEN + 1];
+
+ if (VARSIZE(units) - VARHDRSZ > MAXDATELEN)
+ elog(ERROR, "TIME units '%s' not recognized",
+ DatumGetCString(DirectFunctionCall1(textout,
+ PointerGetDatum(units))));
+ up = VARDATA(units);
+ lp = lowunits;
+ for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
+ *lp++ = tolower((unsigned char) *up++);
+ *lp = '\0';
+
+ type = DecodeUnits(0, lowunits, &val);
+ if (type == UNKNOWN_FIELD)
+ type = DecodeSpecial(0, lowunits, &val);
+
+ if (type == UNITS)
+ {
+ fsec_t fsec;
+ struct tm tt,
+ *tm = &tt;
+
+ time2tm(time, tm, &fsec);
+
+ switch (val)
+ {
+ case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((tm->tm_sec * INT64CONST(1000000)) + fsec);
+#else
+ result = ((tm->tm_sec + fsec) * 1000000);
+#endif
+ break;
+
+ case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((tm->tm_sec * INT64CONST(1000))
+ + (fsec / INT64CONST(1000)));
+#else
+ result = ((tm->tm_sec + fsec) * 1000);
+#endif
+ break;
+
+ case DTK_SECOND:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (tm->tm_sec + (fsec / INT64CONST(1000000)));
+#else
+ result = (tm->tm_sec + fsec);
+#endif
+ break;
+
+ case DTK_MINUTE:
+ result = tm->tm_min;
+ break;
+
+ case DTK_HOUR:
+ result = tm->tm_hour;
+ break;
+
+ case DTK_TZ:
+ case DTK_TZ_MINUTE:
+ case DTK_TZ_HOUR:
+ case DTK_DAY:
+ case DTK_MONTH:
+ case DTK_QUARTER:
+ case DTK_YEAR:
+ case DTK_DECADE:
+ case DTK_CENTURY:
+ case DTK_MILLENNIUM:
+ default:
+ elog(ERROR, "TIME units '%s' not supported",
+ DatumGetCString(DirectFunctionCall1(textout,
+ PointerGetDatum(units))));
+ result = 0;
+ }
+ }
+ else if ((type == RESERV) && (val == DTK_EPOCH))
+ {
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (time / 1000000e0);
+#else
+ result = time;
+#endif
+ }
+ else
+ {
+ elog(ERROR, "TIME units '%s' not recognized",
+ DatumGetCString(DirectFunctionCall1(textout,
+ PointerGetDatum(units))));
+ result = 0;
+ }
+
+ PG_RETURN_FLOAT8(result);
+}
+
/*****************************************************************************
* Time With Time Zone ADT
*****************************************************************************/
+/* tm2timetz()
+ * Convert a tm structure to a time data type.
+ */
+int
+tm2timetz(struct tm * tm, fsec_t fsec, int tz, TimeTzADT *result)
+{
+#ifdef HAVE_INT64_TIMESTAMP
+ result->time = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
+ * INT64CONST(1000000)) + fsec);
+#else
+ result->time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
+#endif
+ result->zone = tz;
+
+ return 0;
+}
+
Datum
timetz_in(PG_FUNCTION_ARGS)
{
@@ -941,7 +1265,7 @@ timetz_in(PG_FUNCTION_ARGS)
#endif
int32 typmod = PG_GETARG_INT32(2);
TimeTzADT *result;
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
int tz;
@@ -956,10 +1280,7 @@ timetz_in(PG_FUNCTION_ARGS)
elog(ERROR, "Bad time external representation '%s'", str);
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
-
- result->time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
- result->zone = tz;
-
+ tm2timetz(tm, fsec, tz, result);
AdjustTimeForTypmod(&(result->time), typmod);
PG_RETURN_TIMETZADT_P(result);
@@ -972,23 +1293,46 @@ timetz_out(PG_FUNCTION_ARGS)
char *result;
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
int tz;
- double trem;
char buf[MAXDATELEN + 1];
+ timetz2tm(time, tm, &fsec, &tz);
+ EncodeTimeOnly(tm, fsec, &tz, DateStyle, buf);
+
+ result = pstrdup(buf);
+ PG_RETURN_CSTRING(result);
+}
+
+/* timetz2tm()
+ * Convert TIME WITH TIME ZONE data type to POSIX time structure.
+ * 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
+ */
+int
+timetz2tm(TimeTzADT *time, struct tm *tm, fsec_t *fsec, int *tzp)
+{
+#ifdef HAVE_INT64_TIMESTAMP
+ tm->tm_hour = (time->time / INT64CONST(3600000000));
+ time->time -= (tm->tm_hour * INT64CONST(3600000000));
+ tm->tm_min = (time->time / INT64CONST(60000000));
+ time->time -= (tm->tm_min * INT64CONST(60000000));
+ tm->tm_sec = (time->time / INT64CONST(1000000));
+ *fsec = (time->time - (tm->tm_sec * INT64CONST(1000000)));
+#else
+ double trem;
+
trem = time->time;
TMODULO(trem, tm->tm_hour, 3600e0);
TMODULO(trem, tm->tm_min, 60e0);
TMODULO(trem, tm->tm_sec, 1e0);
- fsec = trem;
-
- tz = time->zone;
+ *fsec = trem;
+#endif
- EncodeTimeOnly(tm, fsec, &tz, DateStyle, buf);
+ if (tzp != NULL)
+ *tzp = time->zone;
- result = pstrdup(buf);
- PG_RETURN_CSTRING(result);
+ return 0;
}
/* timetz_scale()
@@ -1116,7 +1460,7 @@ timetz_hash(PG_FUNCTION_ARGS)
* sizeof(TimeTzADT), so that any garbage pad bytes in the structure
* won't be included in the hash!
*/
- return hash_any((unsigned char *) key, sizeof(double) + sizeof(int4));
+ return hash_any((unsigned char *) key, sizeof(key->time) + sizeof(key->zone));
}
Datum
@@ -1154,14 +1498,24 @@ timetz_pl_interval(PG_FUNCTION_ARGS)
TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
TimeTzADT *result;
+#ifndef HAVE_INT64_TIMESTAMP
TimeTzADT time1;
+#endif
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
+#ifdef HAVE_INT64_TIMESTAMP
+ result->time = (time->time + span->time);
+ result->time -= (result->time / INT64CONST(86400000000) * INT64CONST(86400000000));
+ if (result->time < INT64CONST(0))
+ result->time += INT64CONST(86400000000);
+#else
result->time = (time->time + span->time);
TMODULO(result->time, time1.time, 86400e0);
if (result->time < 0)
result->time += 86400;
+#endif
+
result->zone = time->zone;
PG_RETURN_TIMETZADT_P(result);
@@ -1176,14 +1530,24 @@ timetz_mi_interval(PG_FUNCTION_ARGS)
TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
TimeTzADT *result;
+#ifndef HAVE_INT64_TIMESTAMP
TimeTzADT time1;
+#endif
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
+#ifdef HAVE_INT64_TIMESTAMP
+ result->time = (time->time - span->time);
+ result->time -= (result->time / INT64CONST(86400000000) * INT64CONST(86400000000));
+ if (result->time < INT64CONST(0))
+ result->time += INT64CONST(86400000000);
+#else
result->time = (time->time - span->time);
TMODULO(result->time, time1.time, 86400e0);
if (result->time < 0)
result->time += 86400;
+#endif
+
result->zone = time->zone;
PG_RETURN_TIMETZADT_P(result);
@@ -1336,9 +1700,11 @@ time_timetz(PG_FUNCTION_ARGS)
TimeTzADT *result;
struct tm tt,
*tm = &tt;
+ fsec_t fsec;
int tz;
GetCurrentTime(tm);
+ time2tm(time, tm, &fsec);
tz = DetermineLocalTimeZone(tm);
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
@@ -1361,19 +1727,18 @@ timestamptz_timetz(PG_FUNCTION_ARGS)
struct tm tt,
*tm = &tt;
int tz;
- double fsec;
+ fsec_t fsec;
char *tzn;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_NULL();
if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
- elog(ERROR, "Unable to convert timestamp to date");
+ elog(ERROR, "Unable to convert timestamptz to timetz");
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
- result->time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
- result->zone = tz;
+ tm2timetz(tm, fsec, tz, result);
PG_RETURN_TIMETZADT_P(result);
}
@@ -1392,7 +1757,12 @@ datetimetz_timestamptz(PG_FUNCTION_ARGS)
TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
TimestampTz result;
- result = date * 86400.0 + time->time + time->zone;
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (((date * INT64CONST(86400000000)) + time->time)
+ + (time->zone * INT64CONST(1000000)));
+#else
+ result = (((date * 86400.0) + time->time) + time->zone);
+#endif
PG_RETURN_TIMESTAMP(result);
}
@@ -1486,19 +1856,13 @@ timetz_part(PG_FUNCTION_ARGS)
if (type == UNITS)
{
- double trem;
double dummy;
int tz;
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
- trem = time->time;
- TMODULO(trem, tm->tm_hour, 3600e0);
- TMODULO(trem, tm->tm_min, 60e0);
- TMODULO(trem, tm->tm_sec, 1e0);
- fsec = trem;
- tz = time->zone;
+ timetz2tm(time, tm, &fsec, &tz);
switch (val)
{
@@ -1517,15 +1881,28 @@ timetz_part(PG_FUNCTION_ARGS)
break;
case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((tm->tm_sec * INT64CONST(1000000)) + fsec);
+#else
result = ((tm->tm_sec + fsec) * 1000000);
+#endif
break;
case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((tm->tm_sec * INT64CONST(1000))
+ + (fsec / INT64CONST(1000)));
+#else
result = ((tm->tm_sec + fsec) * 1000);
+#endif
break;
case DTK_SECOND:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (tm->tm_sec + (fsec / INT64CONST(1000000)));
+#else
result = (tm->tm_sec + fsec);
+#endif
break;
case DTK_MINUTE:
@@ -1551,7 +1928,13 @@ timetz_part(PG_FUNCTION_ARGS)
}
}
else if ((type == RESERV) && (val == DTK_EPOCH))
- result = time->time - time->zone;
+ {
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((time->time / 1000000e0) - time->zone);
+#else
+ result = (time->time - time->zone);
+#endif
+ }
else
{
elog(ERROR, "TIMETZ units '%s' not recognized",
@@ -1598,10 +1981,18 @@ timetz_zone(PG_FUNCTION_ARGS)
if ((type == TZ) || (type == DTZ))
{
tz = val * 60;
- time1 = time->time - time->zone + tz;
+#ifdef HAVE_INT64_TIMESTAMP
+ time1 = (time->time - ((time->zone + tz) * INT64CONST(1000000)));
+ result->time -= ((result->time / time1) * time1);
+ if (result->time < INT64CONST(0))
+ result->time += INT64CONST(86400000000);
+#else
+ time1 = (time->time - time->zone + tz);
TMODULO(result->time, time1, 86400e0);
if (result->time < 0)
result->time += 86400;
+#endif
+
result->zone = tz;
}
else
@@ -1622,7 +2013,6 @@ timetz_izone(PG_FUNCTION_ARGS)
Interval *zone = PG_GETARG_INTERVAL_P(0);
TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
TimeTzADT *result;
- TimeADT time1;
int tz;
if (zone->month != 0)
@@ -1630,14 +2020,28 @@ timetz_izone(PG_FUNCTION_ARGS)
DatumGetCString(DirectFunctionCall1(interval_out,
PointerGetDatum(zone))));
+#ifdef HAVE_INT64_TIMESTAMP
+ tz = -(zone->time / INT64CONST(1000000));
+#else
tz = -(zone->time);
+#endif
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
- time1 = time->time - time->zone + tz;
- TMODULO(result->time, time1, 86400e0);
- if (result->time < 0)
+#ifdef HAVE_INT64_TIMESTAMP
+ result->time = (time->time + ((time->zone - tz) * INT64CONST(1000000)));
+ while (result->time < INT64CONST(0))
+ result->time += INT64CONST(86400000000);
+ while (result->time >= INT64CONST(86400000000))
+ result->time -= INT64CONST(86400000000);
+#else
+ result->time = (time->time + (time->zone - tz));
+ while (result->time < 0)
result->time += 86400;
+ while (result->time >= 86400)
+ result->time -= 86400;
+#endif
+
result->zone = tz;
PG_RETURN_TIMETZADT_P(result);
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 1dd540abb7f..1a908d9d6b7 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.88 2002/02/25 16:17:04 thomas Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.89 2002/04/21 19:48:12 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,12 +28,12 @@
static int DecodeNumber(int flen, char *field,
int fmask, int *tmask,
- struct tm * tm, double *fsec, int *is2digits);
+ struct tm * tm, fsec_t *fsec, int *is2digits);
static int DecodeNumberField(int len, char *str,
int fmask, int *tmask,
- struct tm * tm, double *fsec, int *is2digits);
+ struct tm * tm, fsec_t *fsec, int *is2digits);
static int DecodeTime(char *str, int fmask, int *tmask,
- struct tm * tm, double *fsec);
+ struct tm * tm, fsec_t *fsec);
static int DecodeTimezone(char *str, int *tzp);
static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm);
@@ -865,7 +865,7 @@ ParseDateTime(char *timestr, char *lowstr,
*/
int
DecodeDateTime(char **field, int *ftype, int nf,
- int *dtype, struct tm * tm, double *fsec, int *tzp)
+ int *dtype, struct tm * tm, fsec_t *fsec, int *tzp)
{
int fmask = 0,
tmask,
@@ -1095,9 +1095,15 @@ DecodeDateTime(char **field, int *ftype, int nf,
tmask = DTK_M(SECOND);
if (*cp == '.')
{
- *fsec = strtod(cp, &cp);
+ double frac;
+ frac = strtod(cp, &cp);
if (*cp != '\0')
return -1;
+#ifdef HAVE_INT64_TIMESTAMP
+ *fsec = frac * 1000000;
+#else
+ *fsec = frac;
+#endif
}
break;
@@ -1113,6 +1119,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
***/
tmask = DTK_DATE_M;
j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+ /* fractional Julian Day? */
if (*cp == '.')
{
double time;
@@ -1122,9 +1129,11 @@ DecodeDateTime(char **field, int *ftype, int nf,
return -1;
tmask |= DTK_TIME_M;
- dt2time((time*86400), &tm->tm_hour, &tm->tm_min, fsec);
- tm->tm_sec = *fsec;
- *fsec -= tm->tm_sec;
+#ifdef HAVE_INT64_TIMESTAMP
+ dt2time((time*86400000000), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
+#else
+ dt2time((time*86400), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
+#endif
}
break;
@@ -1505,7 +1514,7 @@ DetermineLocalTimeZone(struct tm * tm)
*/
int
DecodeTimeOnly(char **field, int *ftype, int nf,
- int *dtype, struct tm * tm, double *fsec, int *tzp)
+ int *dtype, struct tm * tm, fsec_t *fsec, int *tzp)
{
int fmask = 0,
tmask,
@@ -1729,9 +1738,11 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
return -1;
tmask |= DTK_TIME_M;
- dt2time((time*86400), &tm->tm_hour, &tm->tm_min, fsec);
- tm->tm_sec = *fsec;
- *fsec -= tm->tm_sec;
+#ifdef HAVE_INT64_TIMESTAMP
+ dt2time((time*86400000000), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
+#else
+ dt2time((time*86400), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
+#endif
}
break;
@@ -1925,10 +1936,18 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
else if ((mer == PM) && (tm->tm_hour != 12))
tm->tm_hour += 12;
+#ifdef HAVE_INT64_TIMESTAMP
+ if (((tm->tm_hour < 0) || (tm->tm_hour > 23))
+ || ((tm->tm_min < 0) || (tm->tm_min > 59))
+ || ((tm->tm_sec < 0) || (tm->tm_sec > 60))
+ || (*fsec < INT64CONST(0)) || (*fsec >= INT64CONST(1000000)))
+ return -1;
+#else
if (((tm->tm_hour < 0) || (tm->tm_hour > 23))
|| ((tm->tm_min < 0) || (tm->tm_min > 59))
|| ((tm->tm_sec < 0) || ((tm->tm_sec + *fsec) >= 60)))
return -1;
+#endif
if ((fmask & DTK_TIME_M) != DTK_TIME_M)
return -1;
@@ -1973,7 +1992,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
static int
DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
{
- double fsec;
+ fsec_t fsec;
int nf = 0;
int i,
@@ -2100,7 +2119,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
* can be used to represent time spans.
*/
static int
-DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
+DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec)
{
char *cp;
@@ -2115,12 +2134,10 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
{
tm->tm_sec = 0;
*fsec = 0;
-
}
else if (*cp != ':')
{
return -1;
-
}
else
{
@@ -2130,9 +2147,22 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
*fsec = 0;
else if (*cp == '.')
{
+#ifdef HAVE_INT64_TIMESTAMP
+ char fstr[MAXDATELEN + 1];
+
+ /* OK, we have at most six digits to work with.
+ * Let's construct a string and then do the conversion
+ * to an integer.
+ */
+ strncpy(fstr, (cp+1), 7);
+ strcpy((fstr+strlen(fstr)), "000000");
+ *(fstr+6) = '\0';
+ *fsec = strtol(fstr, &cp, 10);
+#else
str = cp;
*fsec = strtod(str, &cp);
- if (cp == str)
+#endif
+ if (*cp != '\0')
return -1;
}
else
@@ -2140,10 +2170,19 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
}
/* do a sanity check */
+#ifdef HAVE_INT64_TIMESTAMP
+ if ((tm->tm_hour < 0)
+ || (tm->tm_min < 0) || (tm->tm_min > 59)
+ || (tm->tm_sec < 0) || (tm->tm_sec > 59)
+ || (*fsec >= INT64CONST(1000000)))
+ return -1;
+#else
if ((tm->tm_hour < 0)
|| (tm->tm_min < 0) || (tm->tm_min > 59)
- || (tm->tm_sec < 0) || (tm->tm_sec > 59))
+ || (tm->tm_sec < 0) || (tm->tm_sec > 59)
+ || (*fsec >= 1))
return -1;
+#endif
return 0;
} /* DecodeTime() */
@@ -2154,7 +2193,7 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
*/
static int
DecodeNumber(int flen, char *str, int fmask,
- int *tmask, struct tm * tm, double *fsec, int *is2digits)
+ int *tmask, struct tm * tm, fsec_t *fsec, int *is2digits)
{
int val;
char *cp;
@@ -2193,7 +2232,6 @@ DecodeNumber(int flen, char *str, int fmask,
tm->tm_yday = val;
j2date((date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1),
&tm->tm_year, &tm->tm_mon, &tm->tm_mday);
-
}
/***
@@ -2225,7 +2263,6 @@ DecodeNumber(int flen, char *str, int fmask,
{
*tmask = DTK_M(MONTH);
tm->tm_mon = val;
-
}
/* no year and EuroDates enabled? then could be day */
else if ((EuroDates || (fmask & DTK_M(MONTH)))
@@ -2275,7 +2312,7 @@ DecodeNumber(int flen, char *str, int fmask,
*/
static int
DecodeNumberField(int len, char *str, int fmask,
- int *tmask, struct tm * tm, double *fsec, int *is2digits)
+ int *tmask, struct tm * tm, fsec_t *fsec, int *is2digits)
{
char *cp;
@@ -2284,7 +2321,20 @@ DecodeNumberField(int len, char *str, int fmask,
*/
if ((cp = strchr(str, '.')) != NULL)
{
+#ifdef HAVE_INT64_TIMESTAMP
+ char fstr[MAXDATELEN + 1];
+
+ /* OK, we have at most six digits to care about.
+ * Let's construct a string and then do the conversion
+ * to an integer.
+ */
+ strcpy(fstr, (cp+1));
+ strcpy((fstr+strlen(fstr)), "000000");
+ *(fstr+6) = '\0';
+ *fsec = strtol(fstr, NULL, 10);
+#else
*fsec = strtod(cp, NULL);
+#endif
*cp = '\0';
len = strlen(str);
}
@@ -2501,7 +2551,7 @@ DecodeSpecial(int field, char *lowtoken, int *val)
} /* DecodeSpecial() */
-/* DecodeDateDelta()
+/* DecodeInterval()
* Interpret previously parsed fields for general time interval.
* Return 0 if decoded and -1 if problems.
*
@@ -2512,7 +2562,7 @@ DecodeSpecial(int field, char *lowtoken, int *val)
* preceding an hh:mm:ss field. - thomas 1998-04-30
*/
int
-DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec)
+DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fsec_t *fsec)
{
int is_before = FALSE;
@@ -2523,7 +2573,6 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
int i;
int val;
double fval;
- double sec;
*dtype = DTK_DELTA;
@@ -2631,51 +2680,113 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
switch (type)
{
case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ *fsec += (val + fval);
+#else
*fsec += ((val + fval) * 1e-6);
+#endif
break;
case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ *fsec += ((val + fval) * 1000);
+#else
*fsec += ((val + fval) * 1e-3);
+#endif
break;
case DTK_SECOND:
tm->tm_sec += val;
+#ifdef HAVE_INT64_TIMESTAMP
+ *fsec += (fval * 1000000);
+#else
*fsec += fval;
+#endif
tmask = DTK_M(SECOND);
break;
case DTK_MINUTE:
tm->tm_min += val;
if (fval != 0)
- tm->tm_sec += (fval * 60);
+ {
+ int sec;
+ fval *= 60;
+ sec = fval;
+ tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+ *fsec += ((fval - sec) * 1000000);
+#else
+ *fsec += (fval - sec);
+#endif
+ }
tmask = DTK_M(MINUTE);
break;
case DTK_HOUR:
tm->tm_hour += val;
if (fval != 0)
- tm->tm_sec += (fval * 3600);
+ {
+ int sec;
+ fval *= 3600;
+ sec = fval;
+ tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+ *fsec += ((fval - sec) * 1000000);
+#else
+ *fsec += (fval - sec);
+#endif
+ }
tmask = DTK_M(HOUR);
break;
case DTK_DAY:
tm->tm_mday += val;
if (fval != 0)
- tm->tm_sec += (fval * 86400);
+ {
+ int sec;
+ fval *= 86400;
+ sec = fval;
+ tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+ *fsec += ((fval - sec) * 1000000);
+#else
+ *fsec += (fval - sec);
+#endif
+ }
tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
break;
case DTK_WEEK:
tm->tm_mday += val * 7;
if (fval != 0)
- tm->tm_sec += (fval * (7 * 86400));
+ {
+ int sec;
+ fval *= (7*86400);
+ sec = fval;
+ tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+ *fsec += ((fval - sec) * 1000000);
+#else
+ *fsec += (fval - sec);
+#endif
+ }
tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
break;
case DTK_MONTH:
tm->tm_mon += val;
if (fval != 0)
- tm->tm_sec += (fval * (30 * 86400));
+ {
+ int sec;
+ fval *= (30*86400);
+ sec = fval;
+ tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+ *fsec += ((fval - sec) * 1000000);
+#else
+ *fsec += (fval - sec);
+#endif
+ }
tmask = DTK_M(MONTH);
break;
@@ -2751,7 +2862,14 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
if (*fsec != 0)
{
+ int sec;
+
+#ifdef HAVE_INT64_TIMESTAMP
+ sec = (*fsec / INT64CONST(1000000));
+ *fsec -= (sec * INT64CONST(1000000));
+#else
TMODULO(*fsec, sec, 1e0);
+#endif
tm->tm_sec += sec;
}
@@ -2768,7 +2886,7 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
/* ensure that at least one time field has been found */
return (fmask != 0) ? 0 : -1;
-} /* DecodeDateDelta() */
+} /* DecodeInterval() */
/* DecodeUnits()
@@ -2899,14 +3017,18 @@ EncodeDateOnly(struct tm * tm, int style, char *str)
* Encode time fields only.
*/
int
-EncodeTimeOnly(struct tm * tm, double fsec, int *tzp, int style, char *str)
+EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str)
{
- double sec;
+#ifndef HAVE_INT64_TIMESTAMP
+ fsec_t sec;
+#endif
if ((tm->tm_hour < 0) || (tm->tm_hour > 24))
return -1;
+#ifndef HAVE_INT64_TIMESTAMP
sec = (tm->tm_sec + fsec);
+#endif
sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min);
@@ -2919,14 +3041,23 @@ EncodeTimeOnly(struct tm * tm, double fsec, int *tzp, int style, char *str)
*/
if (fsec != 0)
{
+#ifdef HAVE_INT64_TIMESTAMP
+ sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+ sprintf((str + strlen(str)), ".%06d", fsec);
+#else
sprintf((str + strlen(str)), ":%013.10f", sec);
+#endif
/* chop off trailing pairs of zeros... */
while ((strcmp((str + strlen(str) - 2), "00") == 0)
&& (*(str + strlen(str) - 3) != '.'))
*(str + strlen(str) - 2) = '\0';
}
else
+#ifdef HAVE_INT64_TIMESTAMP
+ sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+#else
sprintf((str + strlen(str)), ":%02.0f", sec);
+#endif
if (tzp != NULL)
{
@@ -2954,158 +3085,191 @@ EncodeTimeOnly(struct tm * tm, double fsec, int *tzp, int style, char *str)
* European - dd/mm/yyyy
*/
int
-EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str)
+EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str)
{
int day,
hour,
min;
- double sec;
+#ifndef HAVE_INT64_TIMESTAMP
+ fsec_t sec;
+#endif
- if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
- return -1;
+ /* Why are we checking only the month field? Change this to an assert...
+ * if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
+ * return -1;
+ */
+ Assert((tm->tm_mon >= 1) && (tm->tm_mon <= 12));
+#ifndef HAVE_INT64_TIMESTAMP
sec = (tm->tm_sec + fsec);
+#endif
switch (style)
{
- /* compatible with ISO date formats */
-
case USE_ISO_DATES:
- if (tm->tm_year > 0)
- {
- sprintf(str, "%04d-%02d-%02d %02d:%02d",
- tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
+ /* Compatible with ISO-8601 date formats */
- /*
- * If we have fractional seconds, then include a decimal
- * point We will do up to 6 fractional digits, and we have
- * rounded any inputs to eliminate anything to the right
- * of 6 digits anyway. If there are no fractional seconds,
- * then do not bother printing a decimal point at all. -
- * thomas 2001-09-29
- */
- if (fsec != 0)
- {
- sprintf((str + strlen(str)), ":%013.10f", sec);
- TrimTrailingZeros(str);
- }
- else
- sprintf((str + strlen(str)), ":%02.0f", sec);
+ sprintf(str, "%04d-%02d-%02d %02d:%02d",
+ ((tm->tm_year > 0)? tm->tm_year: -(tm->tm_year - 1)),
+ tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
- /*
- * tzp == NULL indicates that we don't want *any* time
- * zone info in the output string. *tzn != NULL indicates
- * that we have alpha time zone info available. tm_isdst
- * != -1 indicates that we have a valid time zone
- * translation.
- */
- if ((tzp != NULL) && (tm->tm_isdst >= 0))
- {
- hour = -(*tzp / 3600);
- min = ((abs(*tzp) / 60) % 60);
- sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
- }
+ /*
+ * If we have fractional seconds, then include a decimal
+ * point We will do up to 6 fractional digits, and we have
+ * rounded any inputs to eliminate anything to the right
+ * of 6 digits anyway. If there are no fractional seconds,
+ * then do not bother printing a decimal point at all. -
+ * thomas 2001-09-29
+ */
+#ifdef HAVE_INT64_TIMESTAMP
+ if (fsec != 0)
+ {
+ sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+ sprintf((str + strlen(str)), ".%06d", fsec);
+#else
+ if ((fsec != 0) && (tm->tm_year > 0))
+ {
+ sprintf((str + strlen(str)), ":%013.10f", sec);
+#endif
+ TrimTrailingZeros(str);
}
else
{
- if (tm->tm_hour || tm->tm_min)
- sprintf(str, "%04d-%02d-%02d %02d:%02d %s",
- -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, "BC");
- else
- sprintf(str, "%04d-%02d-%02d %s",
- -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
+ sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+ }
+
+ if (tm->tm_year <= 0)
+ {
+ sprintf((str + strlen(str)), " BC");
+ }
+
+ /*
+ * tzp == NULL indicates that we don't want *any* time
+ * zone info in the output string.
+ * *tzn != NULL indicates that we have alpha time zone
+ * info available.
+ * tm_isdst != -1 indicates that we have a valid time zone
+ * translation.
+ */
+ if ((tzp != NULL) && (tm->tm_isdst >= 0))
+ {
+ hour = -(*tzp / 3600);
+ min = ((abs(*tzp) / 60) % 60);
+ sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
}
break;
- /* compatible with Oracle/Ingres date formats */
case USE_SQL_DATES:
+ /* Compatible with Oracle/Ingres date formats */
+
if (EuroDates)
sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
else
sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
- if (tm->tm_year > 0)
+ sprintf((str + 5), "/%04d %02d:%02d",
+ ((tm->tm_year > 0)? tm->tm_year: -(tm->tm_year - 1)),
+ tm->tm_hour, tm->tm_min);
+
+ /*
+ * If we have fractional seconds, then include a decimal
+ * point We will do up to 6 fractional digits, and we have
+ * rounded any inputs to eliminate anything to the right
+ * of 6 digits anyway. If there are no fractional seconds,
+ * then do not bother printing a decimal point at all. -
+ * thomas 2001-09-29
+ */
+#ifdef HAVE_INT64_TIMESTAMP
+ if (fsec != 0)
+ {
+ sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+ sprintf((str + strlen(str)), ".%06d", fsec);
+#else
+ if ((fsec != 0) && (tm->tm_year > 0))
{
- sprintf((str + 5), "/%04d %02d:%02d",
- tm->tm_year, tm->tm_hour, tm->tm_min);
+ sprintf((str + strlen(str)), ":%013.10f", sec);
+#endif
+ TrimTrailingZeros(str);
+ }
+ else
+ {
+ sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+ }
- /*
- * If we have fractional seconds, then include a decimal
- * point We will do up to 6 fractional digits, and we have
- * rounded any inputs to eliminate anything to the right
- * of 6 digits anyway. If there are no fractional seconds,
- * then do not bother printing a decimal point at all. -
- * thomas 2001-09-29
- */
- if (fsec != 0)
- {
- sprintf((str + strlen(str)), ":%013.10f", sec);
- TrimTrailingZeros(str);
- }
- else
- sprintf((str + strlen(str)), ":%02.0f", sec);
+ if (tm->tm_year <= 0)
+ {
+ sprintf((str + strlen(str)), " BC");
+ }
- if ((tzp != NULL) && (tm->tm_isdst >= 0))
+ if ((tzp != NULL) && (tm->tm_isdst >= 0))
+ {
+ if (*tzn != NULL)
+ sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
+ else
{
- if (*tzn != NULL)
- sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
- else
- {
- hour = -(*tzp / 3600);
- min = ((abs(*tzp) / 60) % 60);
- sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
- }
+ hour = -(*tzp / 3600);
+ min = ((abs(*tzp) / 60) % 60);
+ sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
}
}
- else
- sprintf((str + 5), "/%04d %02d:%02d %s",
- -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC");
break;
- /* German variant on European style */
case USE_GERMAN_DATES:
+ /* German variant on European style */
+
sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
- if (tm->tm_year > 0)
+
+ sprintf((str + 5), ".%04d %02d:%02d",
+ ((tm->tm_year > 0)? tm->tm_year: -(tm->tm_year - 1)),
+ tm->tm_hour, tm->tm_min);
+
+ /*
+ * If we have fractional seconds, then include a decimal
+ * point We will do up to 6 fractional digits, and we have
+ * rounded any inputs to eliminate anything to the right
+ * of 6 digits anyway. If there are no fractional seconds,
+ * then do not bother printing a decimal point at all. -
+ * thomas 2001-09-29
+ */
+#ifdef HAVE_INT64_TIMESTAMP
+ if (fsec != 0)
+ {
+ sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+ sprintf((str + strlen(str)), ".%06d", fsec);
+#else
+ if ((fsec != 0) && (tm->tm_year > 0))
+ {
+ sprintf((str + strlen(str)), ":%013.10f", sec);
+#endif
+ TrimTrailingZeros(str);
+ }
+ else
{
- sprintf((str + 5), ".%04d %02d:%02d",
- tm->tm_year, tm->tm_hour, tm->tm_min);
+ sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+ }
- /*
- * If we have fractional seconds, then include a decimal
- * point We will do up to 6 fractional digits, and we have
- * rounded any inputs to eliminate anything to the right
- * of 6 digits anyway. If there are no fractional seconds,
- * then do not bother printing a decimal point at all. -
- * thomas 2001-09-29
- */
- if (fsec != 0)
- {
- sprintf((str + strlen(str)), ":%013.10f", sec);
- TrimTrailingZeros(str);
- }
- else
- sprintf((str + strlen(str)), ":%02.0f", sec);
+ if (tm->tm_year <= 0)
+ {
+ sprintf((str + strlen(str)), " BC");
+ }
- if ((tzp != NULL) && (tm->tm_isdst >= 0))
+ if ((tzp != NULL) && (tm->tm_isdst >= 0))
+ {
+ if (*tzn != NULL)
+ sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
+ else
{
- if (*tzn != NULL)
- sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
- else
- {
- hour = -(*tzp / 3600);
- min = ((abs(*tzp) / 60) % 60);
- sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
- }
+ hour = -(*tzp / 3600);
+ min = ((abs(*tzp) / 60) % 60);
+ sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
}
}
- else
- sprintf((str + 5), ".%04d %02d:%02d %s",
- -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC");
break;
- /* backward-compatible with traditional Postgres abstime dates */
case USE_POSTGRES_DATES:
default:
+ /* Backward-compatible with traditional Postgres abstime dates */
+
day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
tm->tm_wday = j2day(day);
@@ -3117,52 +3281,58 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
else
sprintf((str + 4), "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
- if (tm->tm_year > 0)
- {
- sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min);
+ sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min);
- /*
- * If we have fractional seconds, then include a decimal
- * point We will do up to 6 fractional digits, and we have
- * rounded any inputs to eliminate anything to the right
- * of 6 digits anyway. If there are no fractional seconds,
- * then do not bother printing a decimal point at all. -
- * thomas 2001-09-29
- */
- if (fsec != 0)
- {
- sprintf((str + strlen(str)), ":%013.10f", sec);
- TrimTrailingZeros(str);
- }
- else
- sprintf((str + strlen(str)), ":%02.0f", sec);
+ /*
+ * If we have fractional seconds, then include a decimal
+ * point We will do up to 6 fractional digits, and we have
+ * rounded any inputs to eliminate anything to the right
+ * of 6 digits anyway. If there are no fractional seconds,
+ * then do not bother printing a decimal point at all. -
+ * thomas 2001-09-29
+ */
+#ifdef HAVE_INT64_TIMESTAMP
+ if (fsec != 0)
+ {
+ sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+ sprintf((str + strlen(str)), ".%06d", fsec);
+#else
+ if ((fsec != 0) && (tm->tm_year > 0))
+ {
+ sprintf((str + strlen(str)), ":%013.10f", sec);
+#endif
+ TrimTrailingZeros(str);
+ }
+ else
+ {
+ sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+ }
- sprintf((str + strlen(str)), " %04d", tm->tm_year);
+ sprintf((str + strlen(str)), " %04d",
+ ((tm->tm_year > 0)? tm->tm_year: -(tm->tm_year - 1)));
+ if (tm->tm_year <= 0)
+ {
+ sprintf((str + strlen(str)), " BC");
+ }
- if ((tzp != NULL) && (tm->tm_isdst >= 0))
+ if ((tzp != NULL) && (tm->tm_isdst >= 0))
+ {
+ if (*tzn != NULL)
+ sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
+ else
{
- if (*tzn != NULL)
- sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
- else
- {
- /*
- * We have a time zone, but no string version. Use
- * the numeric form, but be sure to include a
- * leading space to avoid formatting something
- * which would be rejected by the date/time parser
- * later. - thomas 2001-10-19
- */
- hour = -(*tzp / 3600);
- min = ((abs(*tzp) / 60) % 60);
- sprintf((str + strlen(str)), ((min != 0) ? " %+03d:%02d" : " %+03d"), hour, min);
- }
+ /*
+ * We have a time zone, but no string version. Use
+ * the numeric form, but be sure to include a
+ * leading space to avoid formatting something
+ * which would be rejected by the date/time parser
+ * later. - thomas 2001-10-19
+ */
+ hour = -(*tzp / 3600);
+ min = ((abs(*tzp) / 60) % 60);
+ sprintf((str + strlen(str)), ((min != 0) ? " %+03d:%02d" : " %+03d"), hour, min);
}
}
- else
- {
- sprintf((str + 10), " %02d:%02d %04d %s",
- tm->tm_hour, tm->tm_min, -(tm->tm_year - 1), "BC");
- }
break;
}
@@ -3170,7 +3340,7 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
} /* EncodeDateTime() */
-/* EncodeTimeSpan()
+/* EncodeInterval()
* Interpret time structure as a delta time and convert to string.
*
* Support "traditional Postgres" and ISO-8601 styles.
@@ -3179,7 +3349,7 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
* - thomas 1998-04-30
*/
int
-EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
+EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str)
{
int is_before = FALSE;
int is_nonzero = FALSE;
@@ -3239,8 +3409,14 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
/* fractional seconds? */
if (fsec != 0)
{
+#ifdef HAVE_INT64_TIMESTAMP
+ sprintf(cp, ":%02d", abs(tm->tm_sec));
+ cp += strlen(cp);
+ sprintf(cp, ".%06d", ((fsec >= 0)? fsec: -(fsec)));
+#else
fsec += tm->tm_sec;
sprintf(cp, ":%013.10f", fabs(fsec));
+#endif
TrimTrailingZeros(cp);
cp += strlen(cp);
is_nonzero = TRUE;
@@ -3336,7 +3512,16 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
/* fractional seconds? */
if (fsec != 0)
{
- double sec;
+#ifdef HAVE_INT64_TIMESTAMP
+ if (is_before || ((!is_nonzero) && (tm->tm_sec < 0)))
+ tm->tm_sec = -tm->tm_sec;
+ sprintf(cp, "%s%d.%02d secs", (is_nonzero ? " " : ""),
+ tm->tm_sec, (((int) fsec) / 10000));
+ cp += strlen(cp);
+ if (!is_nonzero)
+ is_before = (fsec < 0);
+#else
+ fsec_t sec;
fsec += tm->tm_sec;
sec = fsec;
@@ -3347,6 +3532,7 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
cp += strlen(cp);
if (!is_nonzero)
is_before = (fsec < 0);
+#endif
is_nonzero = TRUE;
/* otherwise, integer seconds only? */
@@ -3382,7 +3568,7 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
}
return 0;
-} /* EncodeTimeSpan() */
+} /* EncodeInterval() */
void
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 231bad2ca6d..7d28d16001f 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------
* formatting.c
*
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.52 2002/04/03 05:39:29 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.53 2002/04/21 19:48:12 thomas Exp $
*
*
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
@@ -410,7 +410,7 @@ typedef struct
typedef struct TmToChar
{
struct tm tm; /* classic 'tm' struct */
- double fsec; /* milliseconds */
+ fsec_t fsec; /* fractional seconds */
char *tzn; /* timezone */
} TmToChar;
@@ -1831,7 +1831,11 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node, void *data)
case DCH_MS: /* millisecond */
if (flag == TO_CHAR)
{
+#ifdef HAVE_INT64_TIMESTAMP
+ sprintf(inout, "%03d", (int) (tmtc->fsec / INT64CONST(1000)));
+#else
sprintf(inout, "%03d", (int) rint(tmtc->fsec * 1000));
+#endif
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf))
@@ -1874,7 +1878,11 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node, void *data)
case DCH_US: /* microsecond */
if (flag == TO_CHAR)
{
+#ifdef HAVE_INT64_TIMESTAMP
+ sprintf(inout, "%06d", (int) tmtc->fsec);
+#else
sprintf(inout, "%06d", (int) rint(tmtc->fsec * 1000000));
+#endif
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf))
@@ -2868,7 +2876,7 @@ to_timestamp(PG_FUNCTION_ARGS)
date_len,
tz = 0;
struct tm tm;
- double fsec = 0;
+ fsec_t fsec = 0;
ZERO_tm(&tm);
ZERO_tmfc(&tmfc);
@@ -3071,10 +3079,17 @@ to_timestamp(PG_FUNCTION_ARGS)
tm.tm_yday - y[i - 1];
}
+#ifdef HAVE_INT64_TIMESTAMP
+ if (tmfc.ms)
+ fsec += tmfc.ms * 1000;
+ if (tmfc.us)
+ fsec += tmfc.us;
+#else
if (tmfc.ms)
fsec += (double) tmfc.ms / 1000;
if (tmfc.us)
fsec += (double) tmfc.us / 1000000;
+#endif
/* -------------------------------------------------------------- */
diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c
index 6a5eb15d749..685d5e34398 100644
--- a/src/backend/utils/adt/int8.c
+++ b/src/backend/utils/adt/int8.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.37 2002/02/23 01:01:30 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.38 2002/04/21 19:48:12 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,6 +23,7 @@
/* this should be set in pg_config.h, but just in case it wasn't: */
#ifndef INT64_FORMAT
+#warning "Broken pg_config.h should have defined INT64_FORMAT"
#define INT64_FORMAT "%ld"
#endif
diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c
index 299a082facb..651ca00d78e 100644
--- a/src/backend/utils/adt/nabstime.c
+++ b/src/backend/utils/adt/nabstime.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.92 2002/03/06 06:10:13 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.93 2002/04/21 19:48:12 thomas Exp $
*
* NOTES
*
@@ -76,21 +76,6 @@
AbsoluteTimeGetDatum(t1), \
AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
-#ifdef NOT_USED
-static char *unit_tab[] = {
- "second", "seconds", "minute", "minutes",
- "hour", "hours", "day", "days", "week", "weeks",
-"month", "months", "year", "years"};
-
-#define UNITMAXLEN 7 /* max length of a unit name */
-#define NUNITS 14 /* number of different units */
-
-/* table of seconds per unit (month = 30 days, year = 365 days) */
-static int sec_tab[] = {
- 1, 1, 60, 60,
- 3600, 3600, 86400, 86400, 604800, 604800,
-2592000, 2592000, 31536000, 31536000};
-#endif
/*
* Function prototypes -- internal to this file only
@@ -98,12 +83,6 @@ static int sec_tab[] = {
static AbsoluteTime tm2abstime(struct tm * tm, int tz);
static void reltime2tm(RelativeTime time, struct tm * tm);
-
-#ifdef NOT_USED
-static int correct_unit(char *unit, int *unptr);
-static int correct_dir(char *direction, int *signptr);
-#endif
-
static int istinterval(char *i_string,
AbsoluteTime *i_start,
AbsoluteTime *i_end);
@@ -177,7 +156,7 @@ GetCurrentAbsoluteTime(void)
} /* GetCurrentAbsoluteTime() */
-/* GetCurrentAbsoluteTime()
+/* GetCurrentAbsoluteTimeUsec()
* Get the current system time. Set timezone parameters if not specified elsewhere.
* Define HasCTZSet to allow clients to specify the default timezone.
*
@@ -271,13 +250,17 @@ GetCurrentTime(struct tm * tm)
void
-GetCurrentTimeUsec(struct tm * tm, double *fsec)
+GetCurrentTimeUsec(struct tm * tm, fsec_t *fsec)
{
int tz;
int usec;
abstime2tm(GetCurrentTransactionStartTimeUsec(&usec), &tz, tm, NULL);
+#ifdef HAVE_INT64_TIMESTAMP
+ *fsec = usec;
+#else
*fsec = usec * 1.0e-6;
+#endif
return;
} /* GetCurrentTimeUsec() */
@@ -493,7 +476,7 @@ nabstimein(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
AbsoluteTime result;
- double fsec;
+ fsec_t fsec;
int tz = 0;
struct tm date,
*tm = &date;
@@ -713,7 +696,7 @@ timestamp_abstime(PG_FUNCTION_ARGS)
{
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
AbsoluteTime result;
- double fsec;
+ fsec_t fsec;
int tz;
struct tm tt,
*tm = &tt;
@@ -767,7 +750,9 @@ abstime_timestamp(PG_FUNCTION_ARGS)
default:
abstime2tm(abstime, &tz, tm, &tzn);
- result = abstime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400) + tz;
+ if (tm2timestamp(tm, 0, NULL, &result) != 0)
+ elog(ERROR, "Unable convert ABSTIME to TIMESTAMP"
+ "\n\tabstime_timestamp() internal error");
break;
};
@@ -783,7 +768,7 @@ timestamptz_abstime(PG_FUNCTION_ARGS)
{
TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
AbsoluteTime result;
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
@@ -810,6 +795,11 @@ abstime_timestamptz(PG_FUNCTION_ARGS)
{
AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
TimestampTz result;
+ struct tm tt,
+ *tm = &tt;
+ int tz;
+ char zone[MAXDATELEN + 1],
+ *tzn = zone;
switch (abstime)
{
@@ -827,7 +817,10 @@ abstime_timestamptz(PG_FUNCTION_ARGS)
break;
default:
- result = abstime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400);
+ abstime2tm(abstime, &tz, tm, &tzn);
+ if (tm2timestamp(tm, 0, &tz, &result) != 0)
+ elog(ERROR, "Unable convert ABSTIME to TIMESTAMP WITH TIME ZONE"
+ "\n\tabstime_timestamp() internal error");
break;
};
@@ -849,7 +842,7 @@ reltimein(PG_FUNCTION_ARGS)
RelativeTime result;
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
int dtype;
char *field[MAXDATEFIELDS];
int nf,
@@ -860,14 +853,14 @@ reltimein(PG_FUNCTION_ARGS)
elog(ERROR, "Bad (length) reltime external representation '%s'", str);
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
- || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
+ || (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
elog(ERROR, "Bad reltime external representation '%s'", str);
switch (dtype)
{
case DTK_DELTA:
result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec);
- result += (((tm->tm_year * 365) + (tm->tm_mon * 30) + tm->tm_mday) * (24 * 60 * 60));
+ result += ((tm->tm_year * 36525 * 864) + (((tm->tm_mon * 30) + tm->tm_mday) * 86400));
break;
default:
@@ -893,7 +886,7 @@ reltimeout(PG_FUNCTION_ARGS)
char buf[MAXDATELEN + 1];
reltime2tm(time, tm);
- EncodeTimeSpan(tm, 0, DateStyle, buf);
+ EncodeInterval(tm, 0, DateStyle, buf);
result = pstrdup(buf);
PG_RETURN_CSTRING(result);
@@ -903,7 +896,7 @@ reltimeout(PG_FUNCTION_ARGS)
static void
reltime2tm(RelativeTime time, struct tm * tm)
{
- TMODULO(time, tm->tm_year, 31536000);
+ TMODULO(time, tm->tm_year, 31557600);
TMODULO(time, tm->tm_mon, 2592000);
TMODULO(time, tm->tm_mday, 86400);
TMODULO(time, tm->tm_hour, 3600);
@@ -988,7 +981,11 @@ interval_reltime(PG_FUNCTION_ARGS)
RelativeTime time;
int year,
month;
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 span;
+#else
double span;
+#endif
if (interval->month == 0)
{
@@ -1006,7 +1003,13 @@ interval_reltime(PG_FUNCTION_ARGS)
month = interval->month;
}
- span = (((((double) 365 * year) + ((double) 30 * month)) * 86400) + interval->time);
+#ifdef HAVE_INT64_TIMESTAMP
+ span = ((((INT64CONST(365250000) * year) + (INT64CONST(30000000) * month))
+ * INT64CONST(86400)) + interval->time);
+ span /= INT64CONST(1000000);
+#else
+ span = (((((double) 365.25 * year) + ((double) 30 * month)) * 86400) + interval->time);
+#endif
if ((span < INT_MIN) || (span > INT_MAX))
time = INVALID_RELTIME;
@@ -1036,10 +1039,19 @@ reltime_interval(PG_FUNCTION_ARGS)
break;
default:
- TMODULO(reltime, year, 31536000);
- TMODULO(reltime, month, 2592000);
+#ifdef HAVE_INT64_TIMESTAMP
+ year = (reltime / (36525 * 864));
+ reltime -= (year * (36525 * 864));
+ month = (reltime / (30 * 86400));
+ reltime -= (month * (30 * 86400));
+
+ result->time = (reltime * INT64CONST(1000000));
+#else
+ TMODULO(reltime, year, (36525 * 864));
+ TMODULO(reltime, month, (30 * 86400));
result->time = reltime;
+#endif
result->month = ((12 * year) + month);
break;
}
@@ -1090,11 +1102,6 @@ timepl(PG_FUNCTION_ARGS)
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
-#if 0
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
-#endif
-
if (AbsoluteTimeIsReal(t1) &&
RelativeTimeIsValid(t2) &&
((t2 > 0) ? (t1 < NOEND_ABSTIME - t2)
@@ -1114,11 +1121,6 @@ timemi(PG_FUNCTION_ARGS)
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
-#if 0
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
-#endif
-
if (AbsoluteTimeIsReal(t1) &&
RelativeTimeIsValid(t2) &&
((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2)
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 3b1af8df5e1..d045705917d 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.108 2002/04/16 23:08:11 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.109 2002/04/21 19:48:13 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2427,17 +2427,30 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
* assumed average month length of 365.25/12.0 days. Not
* too accurate, but plenty good enough for our purposes.
*/
+#ifdef HAVE_INT64_TIMESTAMP
+ return (interval->time + (interval->month * ((365.25 / 12.0) * 86400000000.0)));
+#else
return interval->time +
interval->month * (365.25 / 12.0 * 24.0 * 60.0 * 60.0);
+#endif
}
case RELTIMEOID:
+#ifdef HAVE_INT64_TIMESTAMP
+ return (DatumGetRelativeTime(value) * 1000000.0);
+#else
return DatumGetRelativeTime(value);
+#endif
case TINTERVALOID:
{
TimeInterval interval = DatumGetTimeInterval(value);
+#ifdef HAVE_INT64_TIMESTAMP
+ if (interval->status != 0)
+ return ((interval->data[1] - interval->data[0]) * 1000000.0);
+#else
if (interval->status != 0)
return interval->data[1] - interval->data[0];
+#endif
return 0; /* for lack of a better idea */
}
case TIMEOID:
@@ -2447,7 +2460,11 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
TimeTzADT *timetz = DatumGetTimeTzADTP(value);
/* use GMT-equivalent time */
+#ifdef HAVE_INT64_TIMESTAMP
+ return (double) (timetz->time + (timetz->zone * 1000000.0));
+#else
return (double) (timetz->time + timetz->zone);
+#endif
}
}
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 5fbdc5b8d89..7637ccf150b 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.65 2002/03/09 17:35:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.66 2002/04/21 19:48:13 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,7 +29,11 @@
#include "utils/builtins.h"
-static double time2t(const int hour, const int min, const double sec);
+#ifdef HAVE_INT64_TIMESTAMP
+static int64 time2t(const int hour, const int min, const int sec, const fsec_t fsec);
+#else
+static double time2t(const int hour, const int min, const int sec, const fsec_t fsec);
+#endif
static int EncodeSpecialTimestamp(Timestamp dt, char *str);
static Timestamp dt2local(Timestamp dt, int timezone);
static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod);
@@ -53,7 +57,7 @@ timestamp_in(PG_FUNCTION_ARGS)
#endif
int32 typmod = PG_GETARG_INT32(2);
Timestamp result;
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
int tz;
@@ -111,7 +115,7 @@ timestamp_out(PG_FUNCTION_ARGS)
char *result;
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
char *tzn = NULL;
char buf[MAXDATELEN + 1];
@@ -147,19 +151,81 @@ timestamp_scale(PG_FUNCTION_ARGS)
static void
AdjustTimestampForTypmod(Timestamp *time, int32 typmod)
{
- if (!TIMESTAMP_NOT_FINITE(*time) &&
- (typmod >= 0) && (typmod <= 13))
+#ifdef HAVE_INT64_TIMESTAMP
+ static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION+1] = {
+ INT64CONST(1000000),
+ INT64CONST(100000),
+ INT64CONST(10000),
+ INT64CONST(1000),
+ INT64CONST(100),
+ INT64CONST(10),
+ INT64CONST(1)
+ };
+
+ static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION+1] = {
+ INT64CONST(-500000),
+ INT64CONST(-50000),
+ INT64CONST(-5000),
+ INT64CONST(-500),
+ INT64CONST(-50),
+ INT64CONST(-5),
+ INT64CONST(0)
+ };
+#else
+ static const double TimestampScales[MAX_TIMESTAMP_PRECISION+1] = {
+ 1,
+ 10,
+ 100,
+ 1000,
+ 10000,
+ 100000,
+ 1000000
+ };
+
+ static const double TimestampOffsets[MAX_TIMESTAMP_PRECISION+1] = {
+ 0.5,
+ 0.05,
+ 0.005,
+ 0.0005,
+ 0.00005,
+ 0.000005,
+ 0.0000005
+ };
+#endif
+
+ if (!TIMESTAMP_NOT_FINITE(*time)
+ && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION))
{
- static double TimestampScale = 1;
- static int32 TimestampTypmod = 0;
+ if ((typmod < 0) || (typmod > MAX_TIMESTAMP_PRECISION))
+ elog(ERROR, "TIMESTAMP(%d) precision must be between %d and %d",
+ typmod, 0, MAX_TIMESTAMP_PRECISION);
- if (typmod != TimestampTypmod)
+#ifdef HAVE_INT64_TIMESTAMP
+ /* we have different truncation behavior depending on sign */
+ if (*time >= INT64CONST(0))
{
- TimestampScale = pow(10.0, typmod);
- TimestampTypmod = typmod;
+ *time = ((*time / TimestampScales[typmod])
+ * TimestampScales[typmod]);
}
-
- *time = (rint(((double) *time) * TimestampScale) / TimestampScale);
+ else
+ {
+ *time = (((*time + TimestampOffsets[typmod]) / TimestampScales[typmod])
+ * TimestampScales[typmod]);
+ }
+#else
+ /* we have different truncation behavior depending on sign */
+ if (*time >= 0)
+ {
+ *time = (rint(((double) *time) * TimestampScales[typmod])
+ / TimestampScales[typmod]);
+ }
+ else
+ {
+ /* Scale and truncate first, then add to help the rounding behavior */
+ *time = (rint((((double) *time) * TimestampScales[typmod]) + TimestampOffsets[typmod])
+ / TimestampScales[typmod]);
+ }
+#endif
}
}
@@ -177,7 +243,7 @@ timestamptz_in(PG_FUNCTION_ARGS)
#endif
int32 typmod = PG_GETARG_INT32(2);
TimestampTz result;
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
int tz;
@@ -236,7 +302,7 @@ timestamptz_out(PG_FUNCTION_ARGS)
int tz;
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
char *tzn;
char buf[MAXDATELEN + 1];
@@ -286,7 +352,7 @@ interval_in(PG_FUNCTION_ARGS)
#endif
int32 typmod = PG_GETARG_INT32(2);
Interval *result;
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
int dtype;
@@ -304,7 +370,7 @@ interval_in(PG_FUNCTION_ARGS)
fsec = 0;
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
- || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
+ || (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
elog(ERROR, "Bad interval external representation '%s'", str);
result = (Interval *) palloc(sizeof(Interval));
@@ -338,13 +404,13 @@ interval_out(PG_FUNCTION_ARGS)
char *result;
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
char buf[MAXDATELEN + 1];
if (interval2tm(*span, tm, &fsec) != 0)
elog(ERROR, "Unable to encode interval; internal coding error");
- if (EncodeTimeSpan(tm, fsec, DateStyle, buf) != 0)
+ if (EncodeInterval(tm, fsec, DateStyle, buf) != 0)
elog(ERROR, "Unable to format interval; internal coding error");
result = pstrdup(buf);
@@ -375,6 +441,48 @@ interval_scale(PG_FUNCTION_ARGS)
static void
AdjustIntervalForTypmod(Interval *interval, int32 typmod)
{
+#ifdef HAVE_INT64_TIMESTAMP
+ static const int64 IntervalScales[MAX_INTERVAL_PRECISION+1] = {
+ INT64CONST(1000000),
+ INT64CONST(100000),
+ INT64CONST(10000),
+ INT64CONST(1000),
+ INT64CONST(100),
+ INT64CONST(10),
+ INT64CONST(1)
+ };
+
+ static const int64 IntervalOffsets[MAX_INTERVAL_PRECISION+1] = {
+ INT64CONST(-500000),
+ INT64CONST(-50000),
+ INT64CONST(-5000),
+ INT64CONST(-500),
+ INT64CONST(-50),
+ INT64CONST(-5),
+ INT64CONST(0)
+ };
+#else
+ static const double IntervalScales[MAX_INTERVAL_PRECISION+1] = {
+ 1000000,
+ 100000,
+ 10000,
+ 1000,
+ 100,
+ 10,
+ 1
+ };
+
+ static const double IntervalOffsets[MAX_INTERVAL_PRECISION+1] = {
+ -500000,
+ -50000,
+ -5000,
+ -500,
+ -50,
+ -5,
+ 0
+ };
+#endif
+
if (typmod != -1)
{
int range = ((typmod >> 16) & 0x7FFF);
@@ -396,102 +504,190 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
}
/* YEAR TO MONTH */
else if (range == (MASK(YEAR) | MASK(MONTH)))
+ {
interval->time = 0;
+ }
else if (range == MASK(DAY))
{
interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+ interval->time = (((int) (interval->time / INT64CONST(86400000000)))
+ * INT64CONST(86400000000));
+#else
interval->time = (((int) (interval->time / 86400)) * 86400);
+#endif
}
else if (range == MASK(HOUR))
{
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 day;
+#else
double day;
+#endif
interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+ day = (interval->time / INT64CONST(86400000000));
+ interval->time -= (day * INT64CONST(86400000000));
+ interval->time = ((interval->time / INT64CONST(3600000000))
+ * INT64CONST(3600000000));
+#else
TMODULO(interval->time, day, 86400.0);
interval->time = (((int) (interval->time / 3600)) * 3600.0);
+#endif
}
else if (range == MASK(MINUTE))
{
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 hour;
+#else
double hour;
+#endif
interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+ hour = (interval->time / INT64CONST(3600000000));
+ interval->time -= (hour * INT64CONST(3600000000));
+ interval->time = ((interval->time / INT64CONST(60000000))
+ * INT64CONST(60000000));
+#else
TMODULO(interval->time, hour, 3600.0);
interval->time = (((int) (interval->time / 60)) * 60);
+#endif
}
else if (range == MASK(SECOND))
{
- double hour;
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 minute;
+#else
+ double minute;
+#endif
interval->month = 0;
- TMODULO(interval->time, hour, 60.0);
+#ifdef HAVE_INT64_TIMESTAMP
+ minute = (interval->time / INT64CONST(60000000));
+ interval->time -= (minute * INT64CONST(60000000));
+#else
+ TMODULO(interval->time, minute, 60.0);
/* interval->time = (int)(interval->time); */
+#endif
}
/* DAY TO HOUR */
else if (range == (MASK(DAY) | MASK(HOUR)))
{
interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+ interval->time = ((interval->time / INT64CONST(3600000000))
+ * INT64CONST(3600000000));
+#else
interval->time = (((int) (interval->time / 3600)) * 3600);
+#endif
}
/* DAY TO MINUTE */
else if (range == (MASK(DAY) | MASK(HOUR) | MASK(MINUTE)))
{
interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+ interval->time = ((interval->time / INT64CONST(60000000))
+ * INT64CONST(60000000));
+#else
interval->time = (((int) (interval->time / 60)) * 60);
+#endif
}
/* DAY TO SECOND */
else if (range == (MASK(DAY) | MASK(HOUR) | MASK(MINUTE) | MASK(SECOND)))
+ {
interval->month = 0;
+ }
/* HOUR TO MINUTE */
else if (range == (MASK(HOUR) | MASK(MINUTE)))
{
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 day;
+#else
double day;
+#endif
interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+ day = (interval->time / INT64CONST(86400000000));
+ interval->time -= (day * INT64CONST(86400000000));
+ interval->time = ((interval->time / INT64CONST(60000000))
+ * INT64CONST(60000000));
+#else
TMODULO(interval->time, day, 86400.0);
interval->time = (((int) (interval->time / 60)) * 60);
+#endif
}
/* HOUR TO SECOND */
else if (range == (MASK(HOUR) | MASK(MINUTE) | MASK(SECOND)))
{
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 day;
+#else
double day;
+#endif
interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+ day = (interval->time / INT64CONST(86400000000));
+ interval->time -= (day * INT64CONST(86400000000));
+#else
TMODULO(interval->time, day, 86400.0);
+#endif
}
/* MINUTE TO SECOND */
else if (range == (MASK(MINUTE) | MASK(SECOND)))
{
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 hour;
+#else
double hour;
+#endif
interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+ hour = (interval->time / INT64CONST(3600000000));
+ interval->time -= (hour * INT64CONST(3600000000));
+#else
TMODULO(interval->time, hour, 3600.0);
+#endif
}
else
elog(ERROR, "AdjustIntervalForTypmod(): internal coding error");
+ /* Need to adjust precision? If not, don't even try! */
if (precision != 0xFFFF)
{
- static double IntervalScale = 1;
- static int IntervalTypmod = 0;
+ if ((precision < 0) || (precision > MAX_INTERVAL_PRECISION))
+ elog(ERROR, "INTERVAL(%d) precision must be between %d and %d",
+ precision, 0, MAX_INTERVAL_PRECISION);
- if (precision != IntervalTypmod)
+#ifdef HAVE_INT64_TIMESTAMP
+ /* we have different truncation behavior depending on sign */
+ if (interval->time >= INT64CONST(0))
{
- IntervalTypmod = precision;
- IntervalScale = pow(10.0, IntervalTypmod);
+ interval->time = ((interval->time / IntervalScales[precision])
+ * IntervalScales[precision]);
}
-
- /*
- * Hmm. For the time field, we can get to a large value since
- * we store everything related to an absolute interval (e.g.
- * years worth of days) in this one field. So we have
- * precision problems doing rint() on this field if the field
- * is too large. This resulted in an annoying "...0001"
- * appended to the printed result on my Linux box. I hate
- * doing an expensive math operation like log10() to avoid
- * this, but what else can we do?? - thomas 2001-10-19
- */
- if ((log10(interval->time) + IntervalTypmod) <= 13)
- interval->time = (rint(interval->time * IntervalScale) / IntervalScale);
+ else
+ {
+ interval->time = (((interval->time + IntervalOffsets[precision]) / IntervalScales[precision])
+ * IntervalScales[precision]);
+ }
+#else
+ /* we have different truncation behavior depending on sign */
+ if (interval->time >= 0)
+ {
+ interval->time = (rint(((double) interval->time) * IntervalScales[precision])
+ / IntervalScales[precision]);
+ }
+ else
+ {
+ interval->time = (rint((((double) interval->time) + IntervalOffsets[precision])
+ * IntervalScales[precision]) / IntervalScales[precision]);
+ }
+#endif
}
}
@@ -524,23 +720,42 @@ now(PG_FUNCTION_ARGS)
sec = GetCurrentTransactionStartTimeUsec(&usec);
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (((sec - ((date2j(2000, 1, 1) - date2j(1970, 1, 1)) * 86400))
+ * INT64CONST(1000000)) + usec);
+#else
result = (sec + (usec * 1.0e-6) - ((date2j(2000, 1, 1) - date2j(1970, 1, 1)) * 86400));
+#endif
PG_RETURN_TIMESTAMPTZ(result);
}
void
-dt2time(Timestamp jd, int *hour, int *min, double *sec)
+dt2time(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 / INT64CONST(3600000000));
+ time -= ((*hour) * INT64CONST(3600000000));
+ *min = (time / INT64CONST(60000000));
+ time -= ((*min) * INT64CONST(60000000));
+ *sec = (time / INT64CONST(1000000));
+ *fsec = (time - (*sec * INT64CONST(1000000)));
+#else
*hour = (time / 3600);
time -= ((*hour) * 3600);
*min = (time / 60);
time -= ((*min) * 60);
- *sec = JROUND(time);
+ *sec = time;
+ *fsec = JROUND(time - *sec);
+#endif
return;
} /* dt2time() */
@@ -558,13 +773,18 @@ dt2time(Timestamp jd, int *hour, int *min, double *sec)
* local time zone. If out of this range, leave as GMT. - tgl 97/05/27
*/
int
-timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
+timestamp2tm(Timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, char **tzn)
{
- double date,
- date0,
- time,
- sec;
- time_t utime;
+#ifdef HAVE_INT64_TIMESTAMP
+ int date,
+ date0;
+ int64 time;
+#else
+ double date,
+ date0;
+ double time;
+#endif
+ time_t utime;
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
struct tm *tx;
@@ -578,9 +798,22 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
* later bypass any calls which adjust the tm fields.
*/
if (HasCTZSet && (tzp != NULL))
+#ifdef HAVE_INT64_TIMESTAMP
+ dt -= (CTimeZone * INT64CONST(1000000));
+#else
dt -= CTimeZone;
+#endif
time = dt;
+#ifdef HAVE_INT64_TIMESTAMP
+ TMODULO(time, date, INT64CONST(86400000000));
+
+ if (time < INT64CONST(0))
+ {
+ time += INT64CONST(86400000000);
+ date -= 1;
+ }
+#else
TMODULO(time, date, 86400e0);
if (time < 0)
@@ -588,6 +821,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
time += 86400;
date -= 1;
}
+#endif
/* Julian day routine does not work for negative Julian days */
if (date < -date0)
@@ -597,10 +831,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
date += date0;
j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
- dt2time(time, &tm->tm_hour, &tm->tm_min, &sec);
-
- *fsec = JROUND(sec);
- TMODULO(*fsec, tm->tm_sec, 1e0);
+ dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
if (tzp != NULL)
{
@@ -626,7 +857,12 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
*/
else if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
{
- utime = (dt + (date0 - date2j(1970, 1, 1)) * 86400);
+#ifdef HAVE_INT64_TIMESTAMP
+ utime = ((dt / INT64CONST(1000000))
+ + ((date0 - date2j(1970, 1, 1)) * INT64CONST(86400)));
+#else
+ utime = (dt + ((date0 - date2j(1970, 1, 1)) * 86400));
+#endif
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
tx = localtime(&utime);
@@ -703,19 +939,27 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
* Also, month is one-based, _not_ zero-based.
*/
int
-tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *result)
+tm2timestamp(struct 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))
return -1;
date = 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));
- *result = (date * 86400 + time);
+ time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
+#ifdef HAVE_INT64_TIMESTAMP
+ *result = ((date * INT64CONST(86400000000)) + time);
+#else
+ *result = ((date * 86400) + time);
+#endif
if (tzp != NULL)
*result = dt2local(*result, -(*tzp));
@@ -727,9 +971,13 @@ tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *result)
* Convert a interval data type to a tm structure.
*/
int
-interval2tm(Interval span, struct tm * tm, float8 *fsec)
+interval2tm(Interval span, struct tm * tm, fsec_t *fsec)
{
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 time;
+#else
double time;
+#endif
if (span.month != 0)
{
@@ -743,45 +991,71 @@ interval2tm(Interval span, struct tm * tm, float8 *fsec)
tm->tm_mon = 0;
}
-#ifdef ROUND_ALL
- time = JROUND(span.time);
-#else
time = span.time;
-#endif
+#ifdef HAVE_INT64_TIMESTAMP
+ tm->tm_mday = (time / INT64CONST(86400000000));
+ time -= (tm->tm_mday * INT64CONST(86400000000));
+ tm->tm_hour = (time / INT64CONST(3600000000));
+ time -= (tm->tm_hour * INT64CONST(3600000000));
+ tm->tm_min = (time / INT64CONST(60000000));
+ time -= (tm->tm_min * INT64CONST(60000000));
+ tm->tm_sec = (time / INT64CONST(1000000));
+ *fsec = (time - (tm->tm_sec * INT64CONST(1000000)));
+#else
TMODULO(time, tm->tm_mday, 86400e0);
TMODULO(time, tm->tm_hour, 3600e0);
TMODULO(time, tm->tm_min, 60e0);
TMODULO(time, tm->tm_sec, 1e0);
*fsec = time;
+#endif
return 0;
} /* interval2tm() */
int
-tm2interval(struct tm * tm, double fsec, Interval *span)
+tm2interval(struct tm * tm, fsec_t fsec, Interval *span)
{
span->month = ((tm->tm_year * 12) + tm->tm_mon);
+#ifdef HAVE_INT64_TIMESTAMP
+ span->time = ((((((((tm->tm_mday * INT64CONST(24))
+ + tm->tm_hour) * INT64CONST(60))
+ + tm->tm_min) * INT64CONST(60))
+ + tm->tm_sec) * INT64CONST(1000000)) + fsec);
+#else
span->time = ((((((tm->tm_mday * 24.0)
+ tm->tm_hour) * 60.0)
+ tm->tm_min) * 60.0)
+ tm->tm_sec);
span->time = JROUND(span->time + fsec);
+#endif
return 0;
} /* tm2interval() */
+#ifdef HAVE_INT64_TIMESTAMP
+static int64
+time2t(const int hour, const int min, const int sec, const fsec_t fsec)
+{
+ return ((((((hour * 60) + min) * 60) + sec) * INT64CONST(1000000)) + fsec);
+} /* time2t() */
+#else
static double
-time2t(const int hour, const int min, const double sec)
+time2t(const int hour, const int min, const int sec, const fsec_t fsec)
{
- return (((hour * 60) + min) * 60) + sec;
+ return ((((hour * 60) + min) * 60) + sec + fsec);
} /* time2t() */
+#endif
static Timestamp
dt2local(Timestamp dt, int tz)
{
+#ifdef HAVE_INT64_TIMESTAMP
+ dt -= (tz * INT64CONST(1000000));
+#else
dt -= tz;
dt = JROUND(dt);
+#endif
return dt;
} /* dt2local() */
@@ -928,15 +1202,28 @@ timestamp_cmp(PG_FUNCTION_ARGS)
static int
interval_cmp_internal(Interval *interval1, Interval *interval2)
{
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 span1,
+ span2;
+#else
double span1,
span2;
+#endif
span1 = interval1->time;
+ span2 = interval2->time;
+
+#ifdef HAVE_INT64_TIMESTAMP
+ if (interval1->month != 0)
+ span1 += ((interval1->month * INT64CONST(30) * INT64CONST(86400000000)));
+ if (interval2->month != 0)
+ span2 += ((interval2->month * INT64CONST(30) * INT64CONST(86400000000)));
+#else
if (interval1->month != 0)
span1 += (interval1->month * (30.0 * 86400));
- span2 = interval2->time;
if (interval2->month != 0)
span2 += (interval2->month * (30.0 * 86400));
+#endif
return ((span1 < span2) ? -1 : (span1 > span2) ? 1 : 0);
}
@@ -1017,7 +1304,7 @@ interval_hash(PG_FUNCTION_ARGS)
* sizeof(Interval), so that any garbage pad bytes in the structure
* won't be included in the hash!
*/
- return hash_any((unsigned char *) key, sizeof(double) + sizeof(int4));
+ return hash_any((unsigned char *) key, sizeof(key->time) + sizeof(key->month));
}
/* overlaps_timestamp() --- implements the SQL92 OVERLAPS operator.
@@ -1195,7 +1482,11 @@ timestamp_mi(PG_FUNCTION_ARGS)
result->time = 0;
}
else
+#ifdef HAVE_INT64_TIMESTAMP
+ result->time = (dt1 - dt2);
+#else
result->time = JROUND(dt1 - dt2);
+#endif
result->month = 0;
@@ -1220,14 +1511,16 @@ timestamp_pl_span(PG_FUNCTION_ARGS)
Timestamp result;
if (TIMESTAMP_NOT_FINITE(timestamp))
+ {
result = timestamp;
+ }
else
{
if (span->month != 0)
{
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
{
@@ -1262,12 +1555,7 @@ timestamp_pl_span(PG_FUNCTION_ARGS)
}
}
-#ifdef ROUND_ALL
- timestamp = JROUND(timestamp + span->time);
-#else
timestamp += span->time;
-#endif
-
result = timestamp;
}
@@ -1316,7 +1604,7 @@ timestamptz_pl_span(PG_FUNCTION_ARGS)
{
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) == 0)
{
@@ -1349,12 +1637,7 @@ timestamptz_pl_span(PG_FUNCTION_ARGS)
}
}
-#ifdef ROUND_ALL
- timestamp = JROUND(timestamp + span->time);
-#else
timestamp += span->time;
-#endif
-
result = timestamp;
}
@@ -1398,17 +1681,29 @@ interval_smaller(PG_FUNCTION_ARGS)
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
Interval *result;
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 span1,
+ span2;
+#else
double span1,
span2;
+#endif
result = (Interval *) palloc(sizeof(Interval));
span1 = interval1->time;
+ span2 = interval2->time;
+#ifdef HAVE_INT64_TIMESTAMP
+ if (interval1->month != 0)
+ span1 += ((interval1->month * INT64CONST(30) * INT64CONST(86400000000)));
+ if (interval2->month != 0)
+ span2 += ((interval2->month * INT64CONST(30) * INT64CONST(86400000000)));
+#else
if (interval1->month != 0)
span1 += (interval1->month * (30.0 * 86400));
- span2 = interval2->time;
if (interval2->month != 0)
span2 += (interval2->month * (30.0 * 86400));
+#endif
if (span2 < span1)
{
@@ -1430,17 +1725,29 @@ interval_larger(PG_FUNCTION_ARGS)
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
Interval *result;
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 span1,
+ span2;
+#else
double span1,
span2;
+#endif
result = (Interval *) palloc(sizeof(Interval));
span1 = interval1->time;
+ span2 = interval2->time;
+#ifdef HAVE_INT64_TIMESTAMP
+ if (interval1->month != 0)
+ span1 += ((interval1->month * INT64CONST(30) * INT64CONST(86400000000)));
+ if (interval2->month != 0)
+ span2 += ((interval2->month * INT64CONST(30) * INT64CONST(86400000000)));
+#else
if (interval1->month != 0)
span1 += (interval1->month * (30.0 * 86400));
- span2 = interval2->time;
if (interval2->month != 0)
span2 += (interval2->month * (30.0 * 86400));
+#endif
if (span2 > span1)
{
@@ -1466,7 +1773,11 @@ interval_pl(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
result->month = (span1->month + span2->month);
+#ifdef HAVE_INT64_TIMESTAMP
+ result->time = (span1->time + span2->time);
+#else
result->time = JROUND(span1->time + span2->time);
+#endif
PG_RETURN_INTERVAL_P(result);
}
@@ -1481,7 +1792,11 @@ interval_mi(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
result->month = (span1->month - span2->month);
+#ifdef HAVE_INT64_TIMESTAMP
+ result->time = (span1->time - span2->time);
+#else
result->time = JROUND(span1->time - span2->time);
+#endif
PG_RETURN_INTERVAL_P(result);
}
@@ -1492,15 +1807,26 @@ interval_mul(PG_FUNCTION_ARGS)
Interval *span1 = PG_GETARG_INTERVAL_P(0);
float8 factor = PG_GETARG_FLOAT8(1);
Interval *result;
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 months;
+#else
double months;
+#endif
result = (Interval *) palloc(sizeof(Interval));
months = (span1->month * factor);
+#ifdef HAVE_INT64_TIMESTAMP
+ result->month = months;
+ result->time = (span1->time * factor);
+ result->time += ((months - result->month) * INT64CONST(30)
+ * INT64CONST(86400000000));
+#else
result->month = rint(months);
result->time = JROUND(span1->time * factor);
/* evaluate fractional months as 30 days */
result->time += JROUND((months - result->month) * 30 * 86400);
+#endif
PG_RETURN_INTERVAL_P(result);
}
@@ -1518,21 +1844,31 @@ mul_d_interval(PG_FUNCTION_ARGS)
Datum
interval_div(PG_FUNCTION_ARGS)
{
- Interval *span1 = PG_GETARG_INTERVAL_P(0);
+ Interval *span = PG_GETARG_INTERVAL_P(0);
float8 factor = PG_GETARG_FLOAT8(1);
Interval *result;
+#ifndef HAVE_INT64_TIMESTAMP
double months;
+#endif
result = (Interval *) palloc(sizeof(Interval));
if (factor == 0.0)
elog(ERROR, "interval_div: divide by 0.0 error");
- months = (span1->month / factor);
+#ifdef HAVE_INT64_TIMESTAMP
+ result->month = (span->month / factor);
+ result->time = (span->time / factor);
+ /* evaluate fractional months as 30 days */
+ result->time += (((span->month - (result->month * factor))
+ * INT64CONST(30) * INT64CONST(86400000000)) / factor);
+#else
+ months = (span->month / factor);
result->month = rint(months);
- result->time = JROUND(span1->time / factor);
+ result->time = JROUND(span->time / factor);
/* evaluate fractional months as 30 days */
result->time += JROUND((months - result->month) * 30 * 86400);
+#endif
PG_RETURN_INTERVAL_P(result);
}
@@ -1641,7 +1977,7 @@ timestamp_age(PG_FUNCTION_ARGS)
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
Interval *result;
- double fsec,
+ fsec_t fsec,
fsec1,
fsec2;
struct tm tt,
@@ -1750,7 +2086,7 @@ timestamptz_age(PG_FUNCTION_ARGS)
TimestampTz dt1 = PG_GETARG_TIMESTAMP(0);
TimestampTz dt2 = PG_GETARG_TIMESTAMP(1);
Interval *result;
- double fsec,
+ fsec_t fsec,
fsec1,
fsec2;
struct tm tt,
@@ -2033,7 +2369,7 @@ timestamp_trunc(PG_FUNCTION_ARGS)
char *up,
*lp,
lowunits[MAXDATELEN + 1];
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
@@ -2079,11 +2415,17 @@ timestamp_trunc(PG_FUNCTION_ARGS)
break;
case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ fsec = ((fsec / 1000) * 1000);
+#else
fsec = rint(fsec * 1000) / 1000;
+#endif
break;
case DTK_MICROSEC:
+#ifndef HAVE_INT64_TIMESTAMP
fsec = rint(fsec * 1000000) / 1000000;
+#endif
break;
default:
@@ -2119,7 +2461,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
char *up,
*lp,
lowunits[MAXDATELEN + 1];
- double fsec;
+ fsec_t fsec;
char *tzn;
struct tm tt,
*tm = &tt;
@@ -2166,10 +2508,16 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
break;
case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ fsec = ((fsec / 1000) * 1000);
+#else
fsec = rint(fsec * 1000) / 1000;
+#endif
break;
case DTK_MICROSEC:
+#ifndef HAVE_INT64_TIMESTAMP
fsec = rint(fsec * 1000000) / 1000000;
+#endif
break;
default:
@@ -2206,7 +2554,7 @@ interval_trunc(PG_FUNCTION_ARGS)
char *up,
*lp,
lowunits[MAXDATELEN + 1];
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
@@ -2253,11 +2601,16 @@ interval_trunc(PG_FUNCTION_ARGS)
break;
case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ fsec = ((fsec / 1000) * 1000);
+#else
fsec = rint(fsec * 1000) / 1000;
+#endif
break;
-
case DTK_MICROSEC:
+#ifndef HAVE_INT64_TIMESTAMP
fsec = rint(fsec * 1000000) / 1000000;
+#endif
break;
default:
@@ -2380,7 +2733,7 @@ timestamp_part(PG_FUNCTION_ARGS)
char *up,
*lp,
lowunits[MAXDATELEN + 1];
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
@@ -2410,15 +2763,27 @@ timestamp_part(PG_FUNCTION_ARGS)
switch (val)
{
case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((tm->tm_sec * 1000000e0) + fsec);
+#else
result = (tm->tm_sec + fsec) * 1000000;
+#endif
break;
case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((tm->tm_sec * 1000e0) + (fsec / 1000e0));
+#else
result = (tm->tm_sec + fsec) * 1000;
+#endif
break;
case DTK_SECOND:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (tm->tm_sec + (fsec / 1000000e0));
+#else
result = (tm->tm_sec + fsec);
+#endif
break;
case DTK_MINUTE:
@@ -2463,7 +2828,13 @@ timestamp_part(PG_FUNCTION_ARGS)
case DTK_JULIAN:
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
- result += (((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec) / 86400e0);
+#ifdef HAVE_INT64_TIMESTAMP
+ result += (((((tm->tm_hour * 60) + tm->tm_min) * 60)
+ + tm->tm_sec + (fsec / 1000000e0)) / 86400e0);
+#else
+ result += (((((tm->tm_hour * 60) + tm->tm_min) * 60)
+ + tm->tm_sec + fsec) / 86400e0);
+#endif
break;
case DTK_TZ:
@@ -2479,7 +2850,7 @@ timestamp_part(PG_FUNCTION_ARGS)
switch (val)
{
case DTK_EPOCH:
- result = timestamp - SetEpochTimestamp();
+ result = ((timestamp - SetEpochTimestamp()) / 1000000e0);
break;
case DTK_DOW:
@@ -2529,7 +2900,7 @@ timestamptz_part(PG_FUNCTION_ARGS)
*lp,
lowunits[MAXDATELEN + 1];
double dummy;
- double fsec;
+ fsec_t fsec;
char *tzn;
struct tm tt,
*tm = &tt;
@@ -2574,15 +2945,27 @@ timestamptz_part(PG_FUNCTION_ARGS)
break;
case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((tm->tm_sec * 1000000e0) + fsec);
+#else
result = (tm->tm_sec + fsec) * 1000000;
+#endif
break;
case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((tm->tm_sec * 1000e0) + (fsec / 1000e0));
+#else
result = (tm->tm_sec + fsec) * 1000;
+#endif
break;
case DTK_SECOND:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (tm->tm_sec + (fsec / 1000000e0));
+#else
result = (tm->tm_sec + fsec);
+#endif
break;
case DTK_MINUTE:
@@ -2627,7 +3010,13 @@ timestamptz_part(PG_FUNCTION_ARGS)
case DTK_JULIAN:
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
- result += (((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec) / 86400e0);
+#ifdef HAVE_INT64_TIMESTAMP
+ result += (((((tm->tm_hour * 60) + tm->tm_min) * 60)
+ + tm->tm_sec + (fsec / 1000000e0)) / 86400e0);
+#else
+ result += (((((tm->tm_hour * 60) + tm->tm_min) * 60)
+ + tm->tm_sec + fsec) / 86400e0);
+#endif
break;
default:
@@ -2641,7 +3030,11 @@ timestamptz_part(PG_FUNCTION_ARGS)
switch (val)
{
case DTK_EPOCH:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((timestamp - SetEpochTimestamp()) / 100000e0);
+#else
result = timestamp - SetEpochTimestamp();
+#endif
break;
case DTK_DOW:
@@ -2689,7 +3082,7 @@ interval_part(PG_FUNCTION_ARGS)
char *up,
*lp,
lowunits[MAXDATELEN + 1];
- double fsec;
+ fsec_t fsec;
struct tm tt,
*tm = &tt;
@@ -2713,17 +3106,29 @@ interval_part(PG_FUNCTION_ARGS)
{
switch (val)
{
- case DTK_MICROSEC:
- result = ((tm->tm_sec + fsec) * 1000000);
- break;
+ case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((tm->tm_sec * 1000000e0) + fsec);
+#else
+ result = (tm->tm_sec + fsec) * 1000000;
+#endif
+ break;
- case DTK_MILLISEC:
- result = ((tm->tm_sec + fsec) * 1000);
- break;
+ case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = ((tm->tm_sec * 1000e0) + (fsec / 1000e0));
+#else
+ result = (tm->tm_sec + fsec) * 1000;
+#endif
+ break;
- case DTK_SECOND:
- result = (tm->tm_sec + fsec);
- break;
+ case DTK_SECOND:
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (tm->tm_sec + (fsec / 1000000e0));
+#else
+ result = (tm->tm_sec + fsec);
+#endif
+ break;
case DTK_MINUTE:
result = tm->tm_min;
@@ -2778,11 +3183,15 @@ interval_part(PG_FUNCTION_ARGS)
}
else if ((type == RESERV) && (val == DTK_EPOCH))
{
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (interval->time / 1000000e0);
+#else
result = interval->time;
+#endif
if (interval->month != 0)
{
result += ((365.25 * 86400) * (interval->month / 12));
- result += ((30 * 86400) * (interval->month % 12));
+ result += ((30.0 * 86400) * (interval->month % 12));
}
}
else
@@ -2799,6 +3208,8 @@ interval_part(PG_FUNCTION_ARGS)
/* timestamp_zone()
* Encode timestamp type with specified time zone.
+ * Returns timestamp with time zone, with the input
+ * rotated from local time to the specified zone.
*/
Datum
timestamp_zone(PG_FUNCTION_ARGS)
@@ -2832,8 +3243,9 @@ timestamp_zone(PG_FUNCTION_ARGS)
if ((type == TZ) || (type == DTZ))
{
- tz = val * 60;
- result = timestamp - tz;
+ tz = -(val * 60);
+
+ result = dt2local(timestamp, tz);
}
else
{
@@ -2846,7 +3258,6 @@ timestamp_zone(PG_FUNCTION_ARGS)
/* timestamp_izone()
* Encode timestamp type with specified time interval as time zone.
- * Require ISO-formatted result, since character-string time zone is not available.
*/
Datum
timestamp_izone(PG_FUNCTION_ARGS)
@@ -2864,8 +3275,13 @@ timestamp_izone(PG_FUNCTION_ARGS)
DatumGetCString(DirectFunctionCall1(interval_out,
PointerGetDatum(zone))));
- tz = -(zone->time);
- result = timestamp - tz;
+#ifdef HAVE_INT64_TIMESTAMP
+ tz = (zone->time / INT64CONST(1000000));
+#else
+ tz = (zone->time);
+#endif
+
+ result = dt2local(timestamp, tz);
PG_RETURN_TIMESTAMPTZ(result);
} /* timestamp_izone() */
@@ -2880,7 +3296,7 @@ timestamp_timestamptz(PG_FUNCTION_ARGS)
TimestampTz result;
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
int tz;
if (TIMESTAMP_NOT_FINITE(timestamp))
@@ -2909,7 +3325,7 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
Timestamp result;
struct tm tt,
*tm = &tt;
- double fsec;
+ fsec_t fsec;
char *tzn;
int tz;
@@ -2928,15 +3344,16 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
}
/* timestamptz_zone()
- * Encode timestamp with time zone type with specified time zone.
+ * Evaluate timestamp with time zone type at the specified time zone.
+ * Returns a timestamp without time zone.
*/
Datum
timestamptz_zone(PG_FUNCTION_ARGS)
{
text *zone = PG_GETARG_TEXT_P(0);
TimestampTz timestamp = PG_GETARG_TIMESTAMP(1);
- text *result;
- TimestampTz dt;
+ Timestamp result;
+
int tz;
int type,
val;
@@ -2944,13 +3361,6 @@ timestamptz_zone(PG_FUNCTION_ARGS)
char *up,
*lp,
lowzone[MAXDATELEN + 1];
- char *tzn,
- upzone[MAXDATELEN + 1];
- double fsec;
- struct tm tt,
- *tm = &tt;
- char buf[MAXDATELEN + 1];
- int len;
if (VARSIZE(zone) - VARHDRSZ > MAXDATELEN)
elog(ERROR, "Time zone '%s' not recognized",
@@ -2965,86 +3375,50 @@ timestamptz_zone(PG_FUNCTION_ARGS)
type = DecodeSpecial(0, lowzone, &val);
if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_TEXT_P(pstrdup(""));
+ PG_RETURN_NULL();
if ((type == TZ) || (type == DTZ))
{
- tm->tm_isdst = ((type == DTZ) ? 1 : 0);
tz = val * 60;
- dt = dt2local(timestamp, tz);
-
- if (timestamp2tm(dt, NULL, tm, &fsec, NULL) != 0)
- elog(ERROR, "Unable to decode TIMESTAMP WITH TIME ZONE"
- "\n\ttimestamptz_zone() internal coding error");
-
- up = upzone;
- lp = lowzone;
- for (i = 0; *lp != '\0'; i++)
- *up++ = toupper((unsigned char) *lp++);
- *up = '\0';
-
- tzn = upzone;
- EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
-
- len = (strlen(buf) + VARHDRSZ);
-
- result = palloc(len);
-
- VARATT_SIZEP(result) = len;
- memmove(VARDATA(result), buf, (len - VARHDRSZ));
+ result = dt2local(timestamp, tz);
}
else
{
elog(ERROR, "Time zone '%s' not recognized", lowzone);
- PG_RETURN_TEXT_P(pstrdup(""));
+ PG_RETURN_NULL();
}
- PG_RETURN_TEXT_P(result);
+ PG_RETURN_TIMESTAMP(result);
} /* timestamptz_zone() */
/* timestamptz_izone()
* Encode timestamp with time zone type with specified time interval as time zone.
- * Require ISO-formatted result, since character-string time zone is not available.
+ * Returns a timestamp without time zone.
*/
Datum
timestamptz_izone(PG_FUNCTION_ARGS)
{
Interval *zone = PG_GETARG_INTERVAL_P(0);
TimestampTz timestamp = PG_GETARG_TIMESTAMP(1);
- text *result;
- TimestampTz dt;
+ Timestamp result;
int tz;
- char *tzn = "";
- double fsec;
- struct tm tt,
- *tm = &tt;
- char buf[MAXDATELEN + 1];
- int len;
if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_TEXT_P(pstrdup(""));
+ PG_RETURN_NULL();
if (zone->month != 0)
elog(ERROR, "INTERVAL time zone '%s' not legal (month specified)",
DatumGetCString(DirectFunctionCall1(interval_out,
PointerGetDatum(zone))));
- tm->tm_isdst = -1;
+#ifdef HAVE_INT64_TIMESTAMP
+ tz = -(zone->time / INT64CONST(1000000));
+#else
tz = -(zone->time);
+#endif
- dt = dt2local(timestamp, tz);
-
- if (timestamp2tm(dt, NULL, tm, &fsec, NULL) != 0)
- elog(ERROR, "Unable to decode TIMESTAMP WITH TIME ZONE"
- "\n\ttimestamptz_izone() internal coding error");
-
- EncodeDateTime(tm, fsec, &tz, &tzn, USE_ISO_DATES, buf);
- len = (strlen(buf) + VARHDRSZ);
+ result = dt2local(timestamp, tz);
- result = palloc(len);
- VARATT_SIZEP(result) = len;
- memmove(VARDATA(result), buf, (len - VARHDRSZ));
-
- PG_RETURN_TEXT_P(result);
+ PG_RETURN_TIMESTAMP(result);
} /* timestamptz_izone() */
diff --git a/src/include/c.h b/src/include/c.h
index 29de3860879..52637717f58 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: c.h,v 1.115 2002/03/29 17:32:55 petere Exp $
+ * $Id: c.h,v 1.116 2002/04/21 19:48:18 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -302,6 +302,10 @@ typedef unsigned long int uint64;
#endif /* not HAVE_LONG_INT_64 and not HAVE_LONG_LONG_INT_64 */
+#if defined(USE_INTEGER_DATETIMES) && !defined(INT64_IS_BUSTED)
+#define HAVE_INT64_TIMESTAMP
+#endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 299cef2bb40..00a00bf1b03 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.121 2002/04/21 00:26:43 tgl Exp $
+ * $Id: catversion.h,v 1.122 2002/04/21 19:48:22 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200204201
+#define CATALOG_VERSION_NO 200204211
#endif
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 2bc01d6b171..27ed668f7b6 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_control.h,v 1.6 2001/11/05 17:46:32 momjian Exp $
+ * $Id: pg_control.h,v 1.7 2002/04/21 19:48:23 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,7 +22,7 @@
/* Version identifier for this pg_control format */
-#define PG_CONTROL_VERSION 71
+#define PG_CONTROL_VERSION 72
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
@@ -106,7 +106,15 @@ typedef struct ControlFileData
*/
uint32 blcksz; /* block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
+
+ uint32 nameDataLen; /* catalog name field width */
+ uint32 funcMaxArgs; /* maximum number of function arguments */
+
+ /* flag indicating internal format of timestamp, interval, time */
+ uint32 enableIntTimes; /* int64 storage enabled? */
+
/* active locales --- "C" if compiled without USE_LOCALE: */
+ uint32 localeBuflen;
char lc_collate[LOCALE_NAME_BUFLEN];
char lc_ctype[LOCALE_NAME_BUFLEN];
} ControlFileData;
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 0cd1f5d96f0..90484c95c8b 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_operator.h,v 1.102 2002/04/16 23:08:11 tgl Exp $
+ * $Id: pg_operator.h,v 1.103 2002/04/21 19:48:23 thomas Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -476,6 +476,8 @@ DATA(insert OID = 1068 ( ">" PGNSP PGUID 0 b t f 1043 1043 16 1066 1067 0 0
DATA(insert OID = 1069 ( ">=" PGNSP PGUID 0 b t f 1043 1043 16 1067 1066 0 0 0 0 varcharge scalargtsel scalargtjoinsel ));
/* date operators */
+DATA(insert OID = 1076 ( "+" PGNSP PGUID 0 b t f 1082 1186 1114 0 0 0 0 0 0 date_pl_interval - - ));
+DATA(insert OID = 1077 ( "-" PGNSP PGUID 0 b t f 1082 1186 1114 0 0 0 0 0 0 date_mi_interval - - ));
DATA(insert OID = 1093 ( "=" PGNSP PGUID 0 b t t 1082 1082 16 1093 1094 1095 1095 1095 1097 date_eq eqsel eqjoinsel ));
DATA(insert OID = 1094 ( "<>" PGNSP PGUID 0 b t f 1082 1082 16 1094 1093 0 0 0 0 date_ne neqsel neqjoinsel ));
DATA(insert OID = 1095 ( "<" PGNSP PGUID 0 b t f 1082 1082 16 1097 1098 0 0 0 0 date_lt scalarltsel scalarltjoinsel ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index f8863d9340f..3cdf0a488e9 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_proc.h,v 1.228 2002/04/18 20:01:10 tgl Exp $
+ * $Id: pg_proc.h,v 1.229 2002/04/21 19:48:23 thomas Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@@ -1280,7 +1280,7 @@ DESCR("convert timetz to text");
/* OIDS 1000 - 1999 */
-DATA(insert OID = 1026 ( timezone PGNSP PGUID 12 f t f t f s 2 25 "1186 1184" 100 0 0 100 timestamptz_izone - _null_ ));
+DATA(insert OID = 1026 ( timezone PGNSP PGUID 12 f t f t f s 2 1186 "1186 1184" 100 0 0 100 timestamptz_izone - _null_ ));
DESCR("time zone");
DATA(insert OID = 1029 ( nullvalue PGNSP PGUID 12 f t f f f i 1 16 "0" 100 0 0 100 nullvalue - _null_ ));
@@ -1414,8 +1414,8 @@ DATA(insert OID = 1156 ( timestamptz_ge PGNSP PGUID 12 f t f t f i 2 16 "1184
DESCR("greater-than-or-equal");
DATA(insert OID = 1157 ( timestamptz_gt PGNSP PGUID 12 f t f t f i 2 16 "1184 1184" 100 0 0 100 timestamp_gt - _null_ ));
DESCR("greater-than");
-DATA(insert OID = 1159 ( timezone PGNSP PGUID 12 f t f t f s 2 25 "25 1184" 100 0 0 100 timestamptz_zone - _null_ ));
-DESCR("time zone");
+DATA(insert OID = 1159 ( timezone PGNSP PGUID 12 f t f t f s 2 1114 "25 1184" 100 0 0 100 timestamptz_zone - _null_ ));
+DESCR("timestamp at a specified time zone");
DATA(insert OID = 1160 ( interval_in PGNSP PGUID 12 f t f t f s 1 1186 "0" 100 0 0 100 interval_in - _null_ ));
DESCR("(internal)");
@@ -1710,13 +1710,13 @@ DATA(insert OID = 1383 ( date_part PGNSP PGUID 14 f t f t f s 2 701 "25 703
DESCR("extract field from reltime");
DATA(insert OID = 1384 ( date_part PGNSP PGUID 14 f t f t f i 2 701 "25 1082" 100 0 0 100 "select date_part($1, cast($2 as timestamp without time zone))" - _null_ ));
DESCR("extract field from date");
-DATA(insert OID = 1385 ( date_part PGNSP PGUID 14 f t f t f i 2 701 "25 1083" 100 0 0 100 "select date_part($1, cast($2 as time with time zone))" - _null_ ));
+DATA(insert OID = 1385 ( date_part PGNSP PGUID 12 f t f t f i 2 701 "25 1083" 100 0 0 100 time_part - _null_ ));
DESCR("extract field from time");
DATA(insert OID = 1386 ( age PGNSP PGUID 14 f t f t f s 1 1186 "1184" 100 0 0 100 "select age(cast(current_date as timestamp with time zone), $1)" - _null_ ));
DESCR("date difference from today preserving months and years");
-DATA(insert OID = 1388 ( timetz PGNSP PGUID 12 f t f t f s 1 1266 "1184" 100 0 0 100 timestamptz_timetz - _null_ ));
-DESCR("convert timestamp to timetz");
+DATA(insert OID = 1388 ( timetz PGNSP PGUID 12 f t f t f s 1 1266 "1184" 100 0 0 100 timestamptz_timetz - _null_ ));
+DESCR("convert timestamptz to timetz");
DATA(insert OID = 1389 ( isfinite PGNSP PGUID 12 f t f t f i 1 16 "1184" 100 0 0 100 timestamp_finite - _null_ ));
DESCR("boolean test");
@@ -2769,6 +2769,8 @@ DESCR("return position of substring");
DATA(insert OID = 2015 ( btrim PGNSP PGUID 12 f t f t f i 2 17 "17 17" 100 0 0 100 byteatrim - _null_ ));
DESCR("trim both ends of string");
+DATA(insert OID = 2019 ( time PGNSP PGUID 12 f t f t f s 1 1083 "1184" 100 0 0 100 timestamptz_time - _null_ ));
+DESCR("convert timestamptz to time");
DATA(insert OID = 2020 ( date_trunc PGNSP PGUID 12 f t f t f i 2 1114 "25 1114" 100 0 0 100 timestamp_trunc - _null_ ));
DESCR("truncate timestamp to specified units");
DATA(insert OID = 2021 ( date_part PGNSP PGUID 12 f t f t f i 2 701 "25 1114" 100 0 0 100 timestamp_part - _null_ ));
@@ -2801,9 +2803,9 @@ DATA(insert OID = 2035 ( timestamp_smaller PGNSP PGUID 12 f t f t f i 2 1114 "1
DESCR("smaller of two");
DATA(insert OID = 2036 ( timestamp_larger PGNSP PGUID 12 f t f t f i 2 1114 "1114 1114" 100 0 0 100 timestamp_larger - _null_ ));
DESCR("larger of two");
-DATA(insert OID = 2037 ( timetz PGNSP PGUID 12 f t f t f s 2 1266 "25 1266" 100 0 0 100 timetz_zone - _null_ ));
+DATA(insert OID = 2037 ( timezone PGNSP PGUID 12 f t f t f s 2 1266 "25 1266" 100 0 0 100 timetz_zone - _null_ ));
DESCR("time with time zone");
-DATA(insert OID = 2038 ( timetz PGNSP PGUID 12 f t f t f i 2 1266 "1186 1266" 100 0 0 100 timetz_izone - _null_ ));
+DATA(insert OID = 2038 ( timezone PGNSP PGUID 12 f t f t f i 2 1266 "1186 1266" 100 0 0 100 timetz_izone - _null_ ));
DESCR("time with time zone");
DATA(insert OID = 2041 ( overlaps PGNSP PGUID 12 f t f f f i 4 16 "1114 1114 1114 1114" 100 0 0 100 overlaps_timestamp - _null_ ));
DESCR("SQL92 interval comparison");
@@ -2843,10 +2845,15 @@ DATA(insert OID = 2058 ( age PGNSP PGUID 12 f t f t f i 2 1186 "1114 1114" 1
DESCR("date difference preserving months and years");
DATA(insert OID = 2059 ( age PGNSP PGUID 14 f t f t f s 1 1186 "1114" 100 0 0 100 "select age(cast(current_date as timestamp without time zone), $1)" - _null_ ));
DESCR("date difference from today preserving months and years");
+
DATA(insert OID = 2069 ( timezone PGNSP PGUID 12 f t f t f s 2 1184 "25 1114" 100 0 0 100 timestamp_zone - _null_ ));
-DESCR("time zone");
+DESCR("timestamp at a specified time zone");
DATA(insert OID = 2070 ( timezone PGNSP PGUID 12 f t f t f s 2 1184 "1186 1114" 100 0 0 100 timestamp_izone - _null_ ));
DESCR("time zone");
+DATA(insert OID = 2071 ( date_pl_interval PGNSP PGUID 14 f t f t f i 2 1114 "1082 1186" 100 0 0 100 "select cast($1 as timestamp without time zone) + $2;" - _null_ ));
+DESCR("add");
+DATA(insert OID = 2072 ( date_mi_interval PGNSP PGUID 14 f t f t f i 2 1114 "1082 1186" 100 0 0 100 "select cast($1 as timestamp without time zone) - $2;" - _null_ ));
+DESCR("subtract");
/* Aggregates (moved here from pg_aggregate for 7.3) */
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 2cae99aaefb..80b904181d3 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -8,7 +8,7 @@
* or in pg_config.h afterwards. Of course, if you edit pg_config.h, then your
* changes will be overwritten the next time you run configure.
*
- * $Id: pg_config.h.in,v 1.22 2002/04/21 00:22:52 ishii Exp $
+ * $Id: pg_config.h.in,v 1.23 2002/04/21 19:48:19 thomas Exp $
*/
#ifndef PG_CONFIG_H
@@ -33,6 +33,9 @@
/* A canonical string containing the version number, platform, and C compiler */
#undef PG_VERSION_STR
+/* Set to 1 if you want 64-bit integer timestamp and interval support (--enable-integer-datetimes) */
+#undef USE_INTEGER_DATETIMES
+
/* Set to 1 if you want cyrillic recode (--enable-recode) */
#undef CYR_RECODE
diff --git a/src/include/utils/date.h b/src/include/utils/date.h
index ca911c0f7f0..209dd74d9dc 100644
--- a/src/include/utils/date.h
+++ b/src/include/utils/date.h
@@ -7,27 +7,41 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: date.h,v 1.17 2001/11/05 17:46:36 momjian Exp $
+ * $Id: date.h,v 1.18 2002/04/21 19:48:31 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef DATE_H
#define DATE_H
+#include "c.h"
#include "fmgr.h"
typedef int32 DateADT;
+#ifdef HAVE_INT64_TIMESTAMP
+typedef int64 TimeADT;
+#else
typedef float8 TimeADT;
+#endif
typedef struct
{
- double time; /* all time units other than months and
- * years */
- int32 zone; /* numeric time zone, in seconds */
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 time; /* all time units other than months and years */
+#else
+ double time; /* all time units other than months and years */
+#endif
+ int32 zone; /* numeric time zone, in seconds */
} TimeTzADT;
+#ifdef HAVE_INT64_TIMESTAMP
+#define MAX_TIME_PRECISION 6
+#else
+#define MAX_TIME_PRECISION 13
+#endif
+
/*
* Macros for fmgr-callable functions.
*
@@ -90,6 +104,7 @@ extern Datum time_larger(PG_FUNCTION_ARGS);
extern Datum time_smaller(PG_FUNCTION_ARGS);
extern Datum time_mi_time(PG_FUNCTION_ARGS);
extern Datum timestamp_time(PG_FUNCTION_ARGS);
+extern Datum timestamptz_time(PG_FUNCTION_ARGS);
extern Datum time_interval(PG_FUNCTION_ARGS);
extern Datum interval_time(PG_FUNCTION_ARGS);
extern Datum text_time(PG_FUNCTION_ARGS);
@@ -97,6 +112,7 @@ extern Datum time_text(PG_FUNCTION_ARGS);
extern Datum time_pl_interval(PG_FUNCTION_ARGS);
extern Datum time_mi_interval(PG_FUNCTION_ARGS);
extern Datum interval_pl_time(PG_FUNCTION_ARGS);
+extern Datum time_part(PG_FUNCTION_ARGS);
extern Datum timetz_in(PG_FUNCTION_ARGS);
extern Datum timetz_out(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h
index 7858498a953..a889bd6c7bc 100644
--- a/src/include/utils/datetime.h
+++ b/src/include/utils/datetime.h
@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: datetime.h,v 1.28 2002/01/01 02:54:33 thomas Exp $
+ * $Id: datetime.h,v 1.29 2002/04/21 19:48:31 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -198,15 +198,26 @@ typedef struct
/* TMODULO()
* Macro to replace modf(), which is broken on some platforms.
+ * t = input and remainder
+ * q = integer part
+ * u = divisor
*/
+#ifdef HAVE_INT64_TIMESTAMP
+#define TMODULO(t,q,u) \
+do { \
+ q = (t / u); \
+ if (q != 0) t -= (q * u); \
+} while(0)
+#else
#define TMODULO(t,q,u) \
do { \
q = ((t < 0)? ceil(t / u): floor(t / u)); \
- if (q != 0) \
- t -= rint(q * u); \
+ if (q != 0) t -= rint(q * u); \
} while(0)
+#endif
-#ifdef __CYGWIN__
+/* Global variable holding time zone information. */
+#if defined(__CYGWIN__) || defined(N_PLAT_NLM)
#define TIMEZONE_GLOBAL _timezone
#else
#define TIMEZONE_GLOBAL timezone
@@ -250,7 +261,7 @@ extern int day_tab[2][13];
extern void GetCurrentTime(struct tm * tm);
-extern void GetCurrentTimeUsec(struct tm * tm, double *fsec);
+extern void GetCurrentTimeUsec(struct tm * tm, fsec_t *fsec);
extern void j2date(int jd, int *year, int *month, int *day);
extern int date2j(int year, int month, int day);
@@ -259,22 +270,22 @@ extern int ParseDateTime(char *timestr, char *lowstr,
int maxfields, int *numfields);
extern int DecodeDateTime(char **field, int *ftype,
int nf, int *dtype,
- struct tm * tm, double *fsec, int *tzp);
+ struct tm * tm, fsec_t *fsec, int *tzp);
extern int DecodeTimeOnly(char **field, int *ftype,
int nf, int *dtype,
- struct tm * tm, double *fsec, int *tzp);
+ struct tm * tm, fsec_t *fsec, int *tzp);
-extern int DecodeDateDelta(char **field, int *ftype,
+extern int DecodeInterval(char **field, int *ftype,
int nf, int *dtype,
- struct tm * tm, double *fsec);
+ struct tm * tm, fsec_t *fsec);
extern int DetermineLocalTimeZone(struct tm * tm);
extern int EncodeDateOnly(struct tm * tm, int style, char *str);
-extern int EncodeTimeOnly(struct tm * tm, double fsec, int *tzp, int style, char *str);
-extern int EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str);
-extern int EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str);
+extern int EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str);
+extern int EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str);
+extern int EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str);
extern int DecodeSpecial(int field, char *lowtoken, int *val);
extern int DecodeUnits(int field, char *lowtoken, int *val);
diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h
index e2db00da38e..e2947e00508 100644
--- a/src/include/utils/int8.h
+++ b/src/include/utils/int8.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: int8.h,v 1.31 2001/11/05 17:46:36 momjian Exp $
+ * $Id: int8.h,v 1.32 2002/04/21 19:48:31 thomas Exp $
*
* NOTES
* These data types are supported on all 64-bit architectures, and may
@@ -15,17 +15,25 @@
* is not currently supported, then please try to make it so, then post
* patches to the postgresql.org hackers mailing list.
*
- * This code was written for and originally appeared in the contrib
- * directory as a user-defined type.
- * - thomas 1998-06-08
- *
*-------------------------------------------------------------------------
*/
#ifndef INT8_H
#define INT8_H
+#include "c.h"
#include "fmgr.h"
+/* this should be set in pg_config.h, but just in case it wasn't: */
+#ifndef INT64_FORMAT
+#warning "Broken pg_config.h should have defined INT64_FORMAT"
+#define INT64_FORMAT "%ld"
+#endif
+
+#ifdef HAVE_LL_CONSTANTS
+#define INT64CONST(x) ((int64) x##LL)
+#else
+#define INT64CONST(x) ((int64) x)
+#endif
extern Datum int8in(PG_FUNCTION_ARGS);
extern Datum int8out(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index 3ea20f3ea24..a4da9dd5d6b 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: timestamp.h,v 1.24 2001/11/05 17:46:36 momjian Exp $
+ * $Id: timestamp.h,v 1.25 2002/04/21 19:48:31 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,8 +18,11 @@
#include <limits.h>
#include <float.h>
+#include "c.h"
#include "fmgr.h"
-
+#ifdef HAVE_INT64_TIMESTAMP
+#include "utils/int8.h"
+#endif
/*
* Timestamp represents absolute time.
@@ -31,16 +34,22 @@
* consisting of a beginning and ending time, not a time span - thomas 97/03/20
*/
+#ifdef HAVE_INT64_TIMESTAMP
+typedef int64 Timestamp;
+typedef int64 TimestampTz;
+#else
typedef double Timestamp;
-
typedef double TimestampTz;
+#endif
typedef struct
{
- double time; /* all time units other than months and
- * years */
- int32 month; /* months and years, after time for
- * alignment */
+#ifdef HAVE_INT64_TIMESTAMP
+ int64 time; /* all time units other than months and years */
+#else
+ double time; /* all time units other than months and years */
+#endif
+ int32 month; /* months and years, after time for alignment */
} Interval;
@@ -50,6 +59,27 @@ typedef struct
* For Timestamp, we make use of the same support routines as for float8.
* Therefore Timestamp is pass-by-reference if and only if float8 is!
*/
+#ifdef HAVE_INT64_TIMESTAMP
+#define DatumGetTimestamp(X) ((Timestamp) DatumGetInt64(X))
+#define DatumGetTimestampTz(X) ((TimestampTz) DatumGetInt64(X))
+#define DatumGetIntervalP(X) ((Interval *) DatumGetPointer(X))
+
+#define TimestampGetDatum(X) Int64GetDatum(X)
+#define TimestampTzGetDatum(X) Int64GetDatum(X)
+#define IntervalPGetDatum(X) PointerGetDatum(X)
+
+#define PG_GETARG_TIMESTAMP(n) PG_GETARG_INT64(n)
+#define PG_GETARG_TIMESTAMPTZ(n) PG_GETARG_INT64(n)
+#define PG_GETARG_INTERVAL_P(n) DatumGetIntervalP(PG_GETARG_DATUM(n))
+
+#define PG_RETURN_TIMESTAMP(x) PG_RETURN_INT64(x)
+#define PG_RETURN_TIMESTAMPTZ(x) PG_RETURN_INT64(x)
+#define PG_RETURN_INTERVAL_P(x) return IntervalPGetDatum(x)
+
+#define DT_NOBEGIN (-INT64CONST(0x7fffffffffffffff) - 1)
+#define DT_NOEND (INT64CONST(0x7fffffffffffffff))
+
+#else
#define DatumGetTimestamp(X) ((Timestamp) DatumGetFloat8(X))
#define DatumGetTimestampTz(X) ((TimestampTz) DatumGetFloat8(X))
#define DatumGetIntervalP(X) ((Interval *) DatumGetPointer(X))
@@ -66,7 +96,6 @@ typedef struct
#define PG_RETURN_TIMESTAMPTZ(x) return TimestampTzGetDatum(x)
#define PG_RETURN_INTERVAL_P(x) return IntervalPGetDatum(x)
-
#ifdef HUGE_VAL
#define DT_NOBEGIN (-HUGE_VAL)
#define DT_NOEND (HUGE_VAL)
@@ -74,6 +103,7 @@ typedef struct
#define DT_NOBEGIN (-DBL_MAX)
#define DT_NOEND (DBL_MAX)
#endif
+#endif
#define TIMESTAMP_NOBEGIN(j) do {j = DT_NOBEGIN;} while (0)
#define TIMESTAMP_IS_NOBEGIN(j) ((j) == DT_NOBEGIN)
@@ -83,8 +113,21 @@ typedef struct
#define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j))
+
+#define MAX_TIMESTAMP_PRECISION 6
+#define MAX_INTERVAL_PRECISION 6
+
+#ifdef HAVE_INT64_TIMESTAMP
+typedef int32 fsec_t;
+
+#define SECONDS_TO_TIMESTAMP(x) (INT64CONST(x000000))
+#else
+typedef double fsec_t;
+
+#define SECONDS_TO_TIMESTAMP(x) (xe0)
#define TIME_PREC_INV 1000000.0
#define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV)
+#endif
/*
@@ -167,13 +210,13 @@ extern Datum now(PG_FUNCTION_ARGS);
/* Internal routines (not fmgr-callable) */
-extern int tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *dt);
+extern int tm2timestamp(struct tm * tm, fsec_t fsec, int *tzp, Timestamp *dt);
extern int timestamp2tm(Timestamp dt, int *tzp, struct tm * tm,
- double *fsec, char **tzn);
-extern void dt2time(Timestamp dt, int *hour, int *min, double *sec);
+ fsec_t *fsec, char **tzn);
+extern void dt2time(Timestamp dt, int *hour, int *min, int *sec, fsec_t *fsec);
-extern int interval2tm(Interval span, struct tm * tm, float8 *fsec);
-extern int tm2interval(struct tm * tm, double fsec, Interval *span);
+extern int interval2tm(Interval span, struct tm * tm, fsec_t *fsec);
+extern int tm2interval(struct tm * tm, fsec_t fsec, Interval *span);
extern Timestamp SetEpochTimestamp(void);
extern void GetEpochTime(struct tm * tm);
diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out
index bcace859ce7..4315019210d 100644
--- a/src/test/regress/expected/horology.out
+++ b/src/test/regress/expected/horology.out
@@ -264,22 +264,22 @@ SELECT date '2001-02-03' + time with time zone '04:05:06 UTC' AS "Date + Time UT
(1 row)
SELECT date '1991-02-03' + interval '2 years' AS "Add Two Years";
- Add Two Years
-------------------------------
- Wed Feb 03 00:00:00 1993 PST
+ Add Two Years
+--------------------------
+ Wed Feb 03 00:00:00 1993
(1 row)
SELECT date '2001-12-13' - interval '2 years' AS "Subtract Two Years";
- Subtract Two Years
-------------------------------
- Mon Dec 13 00:00:00 1999 PST
+ Subtract Two Years
+--------------------------
+ Mon Dec 13 00:00:00 1999
(1 row)
-- subtract time from date should not make sense; use interval instead
SELECT date '1991-02-03' - time '04:05:06' AS "Subtract Time";
- Subtract Time
-------------------------------
- Sat Feb 02 19:54:54 1991 PST
+ Subtract Time
+--------------------------
+ Sat Feb 02 19:54:54 1991
(1 row)
SELECT date '1991-02-03' - time with time zone '04:05:06 UTC' AS "Subtract Time UTC";
@@ -406,7 +406,7 @@ SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
| Sat Feb 14 17:32:01 1998
| Sun Feb 15 17:32:01 1998
| Mon Feb 16 17:32:01 1998
- | Thu Feb 16 17:32 0096 BC
+ | Thu Feb 16 17:32:01 0096 BC
| Sun Feb 16 17:32:01 0098
| Fri Feb 16 17:32:01 0598
| Wed Feb 16 17:32:01 1098
@@ -475,7 +475,7 @@ SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMP_TBL;
| Wed Feb 14 17:32:01 1996
| Thu Feb 15 17:32:01 1996
| Fri Feb 16 17:32:01 1996
- | Mon Feb 16 17:32 0098 BC
+ | Mon Feb 16 17:32:01 0098 BC
| Thu Feb 16 17:32:01 0096
| Tue Feb 16 17:32:01 0596
| Sun Feb 16 17:32:01 1096
@@ -622,7 +622,7 @@ SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL;
| Sat Feb 14 17:32:01 1998 PST
| Sun Feb 15 17:32:01 1998 PST
| Mon Feb 16 17:32:01 1998 PST
- | Thu Feb 16 17:32 0096 BC
+ | Thu Feb 16 17:32:01 0096 BC
| Sun Feb 16 17:32:01 0098
| Fri Feb 16 17:32:01 0598
| Wed Feb 16 17:32:01 1098
@@ -691,7 +691,7 @@ SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL;
| Wed Feb 14 17:32:01 1996 PST
| Thu Feb 15 17:32:01 1996 PST
| Fri Feb 16 17:32:01 1996 PST
- | Mon Feb 16 17:32 0098 BC
+ | Mon Feb 16 17:32:01 0098 BC
| Thu Feb 16 17:32:01 0096
| Tue Feb 16 17:32:01 0596
| Sun Feb 16 17:32:01 1096
@@ -1519,7 +1519,7 @@ SELECT (time '00:00', interval '1 hour')
f
(1 row)
-CREATE TABLE TEMP_TIMESTAMP (f1 timestamp);
+CREATE TABLE TEMP_TIMESTAMP (f1 timestamp with time zone);
-- get some candidate input values
INSERT INTO TEMP_TIMESTAMP (f1)
SELECT d1 FROM TIMESTAMP_TBL
@@ -1883,8 +1883,9 @@ SELECT '' AS "160", d.f1 AS "timestamp", t.f1 AS "interval", d.f1 - t.f1 AS minu
| Sat Sep 22 18:19:20 2001 PDT | @ 14 secs ago | Sat Sep 22 18:19:34 2001 PDT
(160 rows)
-SELECT '' AS "16", d.f1 AS "timestamp", timestamp '1980-01-06 00:00 GMT' AS gpstime_zero,
- d.f1 - timestamp '1980-01-06 00:00 GMT' AS difference
+SELECT '' AS "16", d.f1 AS "timestamp",
+ timestamp with time zone '1980-01-06 00:00 GMT' AS gpstime_zero,
+ d.f1 - timestamp with time zone '1980-01-06 00:00 GMT' AS difference
FROM TEMP_TIMESTAMP d
ORDER BY difference;
16 | timestamp | gpstime_zero | difference
@@ -2305,7 +2306,7 @@ SELECT '' AS two, d1 AS "timestamp", abstime(d1) AS abstime
SELECT '' AS three, f1 as abstime, cast(f1 as timestamp) AS "timestamp"
FROM ABSTIME_TBL WHERE NOT isfinite(f1);
-ERROR: Unable to convert abstime 'invalid' to timestamptz
+ERROR: Unable to convert abstime 'invalid' to timestamp
SELECT '' AS ten, f1 AS interval, reltime(f1) AS reltime
FROM INTERVAL_TBL;
ten | interval | reltime
@@ -2385,7 +2386,7 @@ SELECT '' AS "64", d1 AS us_postgres FROM TIMESTAMP_TBL;
| Fri Feb 14 17:32:01 1997
| Sat Feb 15 17:32:01 1997
| Sun Feb 16 17:32:01 1997
- | Tue Feb 16 17:32 0097 BC
+ | Tue Feb 16 17:32:01 0097 BC
| Sat Feb 16 17:32:01 0097
| Thu Feb 16 17:32:01 0597
| Tue Feb 16 17:32:01 1097
@@ -2467,7 +2468,7 @@ SELECT '' AS "64", d1 AS us_iso FROM TIMESTAMP_TBL;
| 1997-02-14 17:32:01
| 1997-02-15 17:32:01
| 1997-02-16 17:32:01
- | 0097-02-16 17:32 BC
+ | 0097-02-16 17:32:01 BC
| 0097-02-16 17:32:01
| 0597-02-16 17:32:01
| 1097-02-16 17:32:01
@@ -2551,7 +2552,7 @@ SELECT '' AS "64", d1 AS us_sql FROM TIMESTAMP_TBL;
| 02/14/1997 17:32:01
| 02/15/1997 17:32:01
| 02/16/1997 17:32:01
- | 02/16/0097 17:32 BC
+ | 02/16/0097 17:32:01 BC
| 02/16/0097 17:32:01
| 02/16/0597 17:32:01
| 02/16/1097 17:32:01
@@ -2642,7 +2643,7 @@ SELECT '' AS "65", d1 AS european_postgres FROM TIMESTAMP_TBL;
| Fri 14 Feb 17:32:01 1997
| Sat 15 Feb 17:32:01 1997
| Sun 16 Feb 17:32:01 1997
- | Tue 16 Feb 17:32 0097 BC
+ | Tue 16 Feb 17:32:01 0097 BC
| Sat 16 Feb 17:32:01 0097
| Thu 16 Feb 17:32:01 0597
| Tue 16 Feb 17:32:01 1097
@@ -2727,7 +2728,7 @@ SELECT '' AS "65", d1 AS european_iso FROM TIMESTAMP_TBL;
| 1997-02-14 17:32:01
| 1997-02-15 17:32:01
| 1997-02-16 17:32:01
- | 0097-02-16 17:32 BC
+ | 0097-02-16 17:32:01 BC
| 0097-02-16 17:32:01
| 0597-02-16 17:32:01
| 1097-02-16 17:32:01
@@ -2812,7 +2813,7 @@ SELECT '' AS "65", d1 AS european_sql FROM TIMESTAMP_TBL;
| 14/02/1997 17:32:01
| 15/02/1997 17:32:01
| 16/02/1997 17:32:01
- | 16/02/0097 17:32 BC
+ | 16/02/0097 17:32:01 BC
| 16/02/0097 17:32:01
| 16/02/0597 17:32:01
| 16/02/1097 17:32:01
diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out
index ad2f1d7ec97..e7c8cc8086b 100644
--- a/src/test/regress/expected/timestamp.out
+++ b/src/test/regress/expected/timestamp.out
@@ -183,7 +183,7 @@ SELECT '' AS "64", d1 FROM TIMESTAMP_TBL;
| Fri Feb 14 17:32:01 1997
| Sat Feb 15 17:32:01 1997
| Sun Feb 16 17:32:01 1997
- | Tue Feb 16 17:32 0097 BC
+ | Tue Feb 16 17:32:01 0097 BC
| Sat Feb 16 17:32:01 0097
| Thu Feb 16 17:32:01 0597
| Tue Feb 16 17:32:01 1097
@@ -265,11 +265,11 @@ SELECT '' AS "48", d1 FROM TIMESTAMP_TBL
SELECT '' AS "15", d1 FROM TIMESTAMP_TBL
WHERE d1 < timestamp without time zone '1997-01-02';
- 15 | d1
-----+--------------------------
+ 15 | d1
+----+-----------------------------
| -infinity
| Thu Jan 01 00:00:00 1970
- | Tue Feb 16 17:32 0097 BC
+ | Tue Feb 16 17:32:01 0097 BC
| Sat Feb 16 17:32:01 0097
| Thu Feb 16 17:32:01 0597
| Tue Feb 16 17:32:01 1097
@@ -335,7 +335,7 @@ SELECT '' AS "63", d1 FROM TIMESTAMP_TBL
| Fri Feb 14 17:32:01 1997
| Sat Feb 15 17:32:01 1997
| Sun Feb 16 17:32:01 1997
- | Tue Feb 16 17:32 0097 BC
+ | Tue Feb 16 17:32:01 0097 BC
| Sat Feb 16 17:32:01 0097
| Thu Feb 16 17:32:01 0597
| Tue Feb 16 17:32:01 1097
@@ -362,12 +362,12 @@ SELECT '' AS "63", d1 FROM TIMESTAMP_TBL
SELECT '' AS "16", d1 FROM TIMESTAMP_TBL
WHERE d1 <= timestamp without time zone '1997-01-02';
- 16 | d1
-----+--------------------------
+ 16 | d1
+----+-----------------------------
| -infinity
| Thu Jan 01 00:00:00 1970
| Thu Jan 02 00:00:00 1997
- | Tue Feb 16 17:32 0097 BC
+ | Tue Feb 16 17:32:01 0097 BC
| Sat Feb 16 17:32:01 0097
| Thu Feb 16 17:32:01 0597
| Tue Feb 16 17:32:01 1097
diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out
index 1741add0ac0..403a0bbd4af 100644
--- a/src/test/regress/expected/timestamptz.out
+++ b/src/test/regress/expected/timestamptz.out
@@ -178,7 +178,7 @@ SELECT '' AS "64", d1 FROM TIMESTAMPTZ_TBL;
| Fri Feb 14 17:32:01 1997 PST
| Sat Feb 15 17:32:01 1997 PST
| Sun Feb 16 17:32:01 1997 PST
- | Tue Feb 16 17:32 0097 BC
+ | Tue Feb 16 17:32:01 0097 BC
| Sat Feb 16 17:32:01 0097
| Thu Feb 16 17:32:01 0597
| Tue Feb 16 17:32:01 1097
@@ -264,7 +264,7 @@ SELECT '' AS "15", d1 FROM TIMESTAMPTZ_TBL
----+------------------------------
| -infinity
| Wed Dec 31 16:00:00 1969 PST
- | Tue Feb 16 17:32 0097 BC
+ | Tue Feb 16 17:32:01 0097 BC
| Sat Feb 16 17:32:01 0097
| Thu Feb 16 17:32:01 0597
| Tue Feb 16 17:32:01 1097
@@ -330,7 +330,7 @@ SELECT '' AS "63", d1 FROM TIMESTAMPTZ_TBL
| Fri Feb 14 17:32:01 1997 PST
| Sat Feb 15 17:32:01 1997 PST
| Sun Feb 16 17:32:01 1997 PST
- | Tue Feb 16 17:32 0097 BC
+ | Tue Feb 16 17:32:01 0097 BC
| Sat Feb 16 17:32:01 0097
| Thu Feb 16 17:32:01 0597
| Tue Feb 16 17:32:01 1097
@@ -362,7 +362,7 @@ SELECT '' AS "16", d1 FROM TIMESTAMPTZ_TBL
| -infinity
| Wed Dec 31 16:00:00 1969 PST
| Thu Jan 02 00:00:00 1997 PST
- | Tue Feb 16 17:32 0097 BC
+ | Tue Feb 16 17:32:01 0097 BC
| Sat Feb 16 17:32:01 0097
| Thu Feb 16 17:32:01 0597
| Tue Feb 16 17:32:01 1097
diff --git a/src/test/regress/sql/horology.sql b/src/test/regress/sql/horology.sql
index 019c3e9ffd7..136e6c6c651 100644
--- a/src/test/regress/sql/horology.sql
+++ b/src/test/regress/sql/horology.sql
@@ -214,7 +214,7 @@ SELECT (time '00:00', interval '1 hour')
SELECT (time '00:00', interval '1 hour')
OVERLAPS (time '01:30', interval '1 day') AS "False";
-CREATE TABLE TEMP_TIMESTAMP (f1 timestamp);
+CREATE TABLE TEMP_TIMESTAMP (f1 timestamp with time zone);
-- get some candidate input values
@@ -236,8 +236,9 @@ SELECT '' AS "160", d.f1 AS "timestamp", t.f1 AS "interval", d.f1 - t.f1 AS minu
WHERE isfinite(d.f1)
ORDER BY minus, "timestamp", "interval";
-SELECT '' AS "16", d.f1 AS "timestamp", timestamp '1980-01-06 00:00 GMT' AS gpstime_zero,
- d.f1 - timestamp '1980-01-06 00:00 GMT' AS difference
+SELECT '' AS "16", d.f1 AS "timestamp",
+ timestamp with time zone '1980-01-06 00:00 GMT' AS gpstime_zero,
+ d.f1 - timestamp with time zone '1980-01-06 00:00 GMT' AS difference
FROM TEMP_TIMESTAMP d
ORDER BY difference;