summaryrefslogtreecommitdiff
path: root/src/backend/utils
diff options
context:
space:
mode:
authorThomas G. Lockhart2002-04-21 19:52:18 +0000
committerThomas G. Lockhart2002-04-21 19:52:18 +0000
commit547df0cc853c3fe70dbf33e241cbe46f5e441b3e (patch)
tree1cc84e876fb28cae976d53ad64e6fab4a5c22e66 /src/backend/utils
parent3fab49325de7924b051ea25ee8d1436d3aff6b28 (diff)
Support alternate storage scheme of 64-bit integer for date/time types.
Use "--enable-integer-datetimes" in configuration to use this rather than the original float8 storage. I would recommend the integer-based storage for any platform on which it is available. We perhaps should make this the default for the production release. Change timezone(timestamptz) results to return timestamp rather than a character string. Formerly, we didn't have a way to represent timestamps with an explicit time zone other than freezing the info into a string. Now, we can reasonably omit the explicit time zone from the result and return a timestamp with values appropriate for the specified time zone. Much cleaner, and if you need the time zone in the result you can put it into a character string pretty easily anyway. Allow fractional seconds in date/time types even for dates prior to 1BC. Limit timestamp data types to 6 decimal places of precision. Just right for a micro-second storage of int8 date/time types, and reduces the number of places ad-hoc rounding was occuring for the float8-based types. Use lookup tables for precision/rounding calculations for timestamp and interval types. Formerly used pow() to calculate the desired value but with a more limited range there is no reason to not type in a lookup table. Should be *much* better performance, though formerly there were some optimizations to help minimize the number of times pow() was called. Define a HAVE_INT64_TIMESTAMP variable. Based on the configure option "--enable-integer-datetimes" and the existing internal INT64_IS_BUSTED. Add explicit date/interval operators and functions for addition and subtraction. Formerly relied on implicit type promotion from date to timestamp with time zone. Change timezone conversion functions for the timetz type from "timetz()" to "timezone()". This is consistant with other time zone coersion functions for other types. Bump the catalog version to 200204201. Fix up regression tests to reflect changes in fractional seconds representation for date/times in BC eras. All regression tests pass on my Linux box.
Diffstat (limited to 'src/backend/utils')
-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
7 files changed, 1460 insertions, 461 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() */