aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r--src/backend/utils/adt/date.c268
-rw-r--r--src/backend/utils/adt/datetime.c210
-rw-r--r--src/backend/utils/adt/format_type.c6
-rw-r--r--src/backend/utils/adt/formatting.c35
-rw-r--r--src/backend/utils/adt/nabstime.c752
-rw-r--r--src/backend/utils/adt/timestamp.c1370
6 files changed, 1665 insertions, 976 deletions
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 4504f5f043c..36b3a52de25 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -8,21 +8,24 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.57 2001/05/03 19:00:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.58 2001/09/28 08:09:10 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include <ctype.h>
#include <limits.h>
#include <time.h>
#include <float.h>
#include "access/hash.h"
#include "miscadmin.h"
+#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/nabstime.h"
+#include "utils/timestamp.h"
/*****************************************************************************
@@ -58,13 +61,13 @@ date_in(PG_FUNCTION_ARGS)
break;
case DTK_CURRENT:
+ elog(ERROR, "Date CURRENT no longer supported"
+ "\n\tdate_in() internal coding error");
GetCurrentTime(tm);
break;
case DTK_EPOCH:
- tm->tm_year = 1970;
- tm->tm_mon = 1;
- tm->tm_mday = 1;
+ GetEpochTime(tm);
break;
default:
@@ -224,6 +227,46 @@ date_timestamp(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Timestamp result;
+
+ /* date is days since 2000, timestamp is seconds since same... */
+ result = dateVal * 86400.0;
+
+ PG_RETURN_TIMESTAMP(result);
+}
+
+
+/* timestamp_date()
+ * Convert timestamp to date data type.
+ */
+Datum
+timestamp_date(PG_FUNCTION_ARGS)
+{
+ Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
+ DateADT result;
+ struct tm tt,
+ *tm = &tt;
+ double 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");
+
+ result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
+
+ PG_RETURN_DATEADT(result);
+}
+
+
+/* date_timestamptz()
+ * Convert date to timestamp with time zone data type.
+ */
+Datum
+date_timestamptz(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ TimestampTz result;
struct tm tt,
*tm = &tt;
time_t utime;
@@ -259,32 +302,25 @@ date_timestamp(PG_FUNCTION_ARGS)
}
-/* timestamp_date()
- * Convert timestamp to date data type.
+/* timestamptz_date()
+ * Convert timestamp with time zone to date data type.
*/
Datum
-timestamp_date(PG_FUNCTION_ARGS)
+timestamptz_date(PG_FUNCTION_ARGS)
{
- Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
+ TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
DateADT result;
struct tm tt,
*tm = &tt;
- int tz;
double fsec;
+ int tz;
char *tzn;
if (TIMESTAMP_NOT_FINITE(timestamp))
- elog(ERROR, "Unable to convert timestamp to date");
+ PG_RETURN_NULL();
- if (TIMESTAMP_IS_EPOCH(timestamp))
- timestamp2tm(SetTimestamp(timestamp), NULL, tm, &fsec, NULL);
- else if (TIMESTAMP_IS_CURRENT(timestamp))
- timestamp2tm(SetTimestamp(timestamp), &tz, tm, &fsec, &tzn);
- else
- {
- if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
- elog(ERROR, "Unable to convert timestamp to date");
- }
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
+ elog(ERROR, "Unable to convert timestamp to date");
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
@@ -316,15 +352,6 @@ abstime_date(PG_FUNCTION_ARGS)
* will be set
*/
- case EPOCH_ABSTIME:
- result = date2j(1970, 1, 1) - date2j(2000, 1, 1);
- break;
-
- case CURRENT_ABSTIME:
- GetCurrentTime(tm);
- result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
- break;
-
default:
abstime2tm(abstime, &tz, tm, NULL);
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
@@ -664,22 +691,13 @@ timestamp_time(PG_FUNCTION_ARGS)
TimeADT result;
struct tm tt,
*tm = &tt;
- int tz;
double fsec;
- char *tzn;
if (TIMESTAMP_NOT_FINITE(timestamp))
- elog(ERROR, "Unable to convert timestamp to date");
+ PG_RETURN_NULL();
- if (TIMESTAMP_IS_EPOCH(timestamp))
- timestamp2tm(SetTimestamp(timestamp), NULL, tm, &fsec, NULL);
- else if (TIMESTAMP_IS_CURRENT(timestamp))
- timestamp2tm(SetTimestamp(timestamp), &tz, tm, &fsec, &tzn);
- else
- {
- if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
- elog(ERROR, "Unable to convert timestamp to date");
- }
+ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) != 0)
+ elog(ERROR, "Unable to convert timestamp to date");
result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
@@ -736,6 +754,24 @@ interval_time(PG_FUNCTION_ARGS)
PG_RETURN_TIMEADT(result);
}
+/* time_mi_time()
+ * Subtract two times to produce an interval.
+ */
+Datum
+time_mi_time(PG_FUNCTION_ARGS)
+{
+ TimeADT time1 = PG_GETARG_TIMEADT(0);
+ TimeADT time2 = PG_GETARG_TIMEADT(1);
+ Interval *result;
+
+ result = (Interval *) palloc(sizeof(Interval));
+
+ result->time = time2 - time1;
+ result->month = 0;
+
+ PG_RETURN_INTERVAL_P(result);
+}
+
/* time_pl_interval()
* Add interval to time.
*/
@@ -918,7 +954,12 @@ timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
* If same GMT time, sort by timezone; we only want to say that two
* timetz's are equal if both the time and zone parts are equal.
*/
- return time1->zone - time2->zone;
+ if (time1->zone > time2->zone)
+ return 1;
+ if (time1->zone < time2->zone)
+ return -1;
+
+ return 0;
}
Datum
@@ -1199,13 +1240,48 @@ overlaps_timetz(PG_FUNCTION_ARGS)
#undef TIMETZ_LT
}
-/* timestamp_timetz()
+
+Datum
+timetz_time(PG_FUNCTION_ARGS)
+{
+ TimeTzADT *timetz = PG_GETARG_TIMETZADT_P(0);
+ TimeADT result;
+
+ /* swallow the time zone and just return the time */
+ result = timetz->time;
+
+ PG_RETURN_TIMEADT(result);
+}
+
+
+Datum
+time_timetz(PG_FUNCTION_ARGS)
+{
+ TimeADT time = PG_GETARG_TIMEADT(0);
+ TimeTzADT *result;
+ struct tm tt,
+ *tm = &tt;
+ int tz;
+
+ GetCurrentTime(tm);
+ tz = DetermineLocalTimeZone(tm);
+
+ result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
+
+ result->time = time;
+ result->zone = tz;
+
+ PG_RETURN_TIMETZADT_P(result);
+}
+
+
+/* timestamptz_timetz()
* Convert timestamp to timetz data type.
*/
Datum
-timestamp_timetz(PG_FUNCTION_ARGS)
+timestamptz_timetz(PG_FUNCTION_ARGS)
{
- Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
+ TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
TimeTzADT *result;
struct tm tt,
*tm = &tt;
@@ -1214,20 +1290,10 @@ timestamp_timetz(PG_FUNCTION_ARGS)
char *tzn;
if (TIMESTAMP_NOT_FINITE(timestamp))
- elog(ERROR, "Unable to convert timestamp to date");
+ PG_RETURN_NULL();
- if (TIMESTAMP_IS_EPOCH(timestamp))
- {
- timestamp2tm(SetTimestamp(timestamp), NULL, tm, &fsec, NULL);
- tz = 0;
- }
- else if (TIMESTAMP_IS_CURRENT(timestamp))
- timestamp2tm(SetTimestamp(timestamp), &tz, tm, &fsec, &tzn);
- else
- {
- if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
- elog(ERROR, "Unable to convert timestamp to date");
- }
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
+ elog(ERROR, "Unable to convert timestamp to date");
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
@@ -1238,18 +1304,18 @@ timestamp_timetz(PG_FUNCTION_ARGS)
}
-/* datetimetz_timestamp()
- * Convert date and timetz to timestamp data type.
+/* datetimetz_timestamptz()
+ * Convert date and timetz to timestamp with time zone data type.
* Timestamp is stored in GMT, so add the time zone
* stored with the timetz to the result.
* - thomas 2000-03-10
*/
Datum
-datetimetz_timestamp(PG_FUNCTION_ARGS)
+datetimetz_timestamptz(PG_FUNCTION_ARGS)
{
DateADT date = PG_GETARG_DATEADT(0);
TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
- Timestamp result;
+ TimestampTz result;
result = date * 86400.0 + time->time + time->zone;
@@ -1310,3 +1376,83 @@ text_timetz(PG_FUNCTION_ARGS)
return DirectFunctionCall1(timetz_in,
CStringGetDatum(dstr));
}
+
+/* timetz_zone()
+ * Encode time with time zone type with specified time zone.
+ */
+Datum
+timetz_zone(PG_FUNCTION_ARGS)
+{
+ text *zone = PG_GETARG_TEXT_P(0);
+ TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
+ TimeTzADT *result;
+ TimeADT time1;
+ int tz;
+ int type,
+ val;
+ int i;
+ char *up,
+ *lp,
+ lowzone[MAXDATELEN + 1];
+
+ if (VARSIZE(zone) - VARHDRSZ > MAXDATELEN)
+ elog(ERROR, "Time zone '%s' not recognized",
+ DatumGetCString(DirectFunctionCall1(textout,
+ PointerGetDatum(zone))));
+ up = VARDATA(zone);
+ lp = lowzone;
+ for (i = 0; i < (VARSIZE(zone) - VARHDRSZ); i++)
+ *lp++ = tolower((unsigned char) *up++);
+ *lp = '\0';
+
+ type = DecodeSpecial(0, lowzone, &val);
+
+ result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
+
+ if ((type == TZ) || (type == DTZ))
+ {
+ tz = val * 60;
+ time1 = time->time - time->zone + tz;
+ TMODULO(result->time, time1, 86400e0);
+ if (result->time < 0)
+ result->time += 86400;
+ result->zone = tz;
+ }
+ else
+ {
+ elog(ERROR, "Time zone '%s' not recognized", lowzone);
+ PG_RETURN_NULL();
+ }
+
+ PG_RETURN_TIMETZADT_P(result);
+} /* timetz_zone() */
+
+/* timetz_izone()
+ * Encode time with time zone type with specified time interval as time zone.
+ */
+Datum
+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)
+ elog(ERROR, "INTERVAL time zone '%s' not legal (month specified)",
+ DatumGetCString(DirectFunctionCall1(interval_out,
+ PointerGetDatum(zone))));
+
+ tz = -(zone->time);
+
+ result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
+
+ time1 = time->time - time->zone + tz;
+ TMODULO(result->time, time1, 86400e0);
+ if (result->time < 0)
+ result->time += 86400;
+ result->zone = tz;
+
+ PG_RETURN_TIMETZADT_P(result);
+} /* timetz_izone() */
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 7095f24de73..28ca77b64ea 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.66 2001/07/10 01:41:47 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.67 2001/09/28 08:09:10 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,13 +29,13 @@
#define ROUND_ALL 1
static int DecodeNumber(int flen, char *field,
- int fmask, int *tmask,
- struct tm * tm, double *fsec, int *is2digits);
+ int fmask, int *tmask,
+ struct tm * tm, double *fsec, int *is2digits);
static int DecodeNumberField(int len, char *str,
- int fmask, int *tmask,
- struct tm * tm, double *fsec, int *is2digits);
+ int fmask, int *tmask,
+ struct tm * tm, double *fsec, int *is2digits);
static int DecodeTime(char *str, int fmask, int *tmask,
- struct tm * tm, double *fsec);
+ struct tm * tm, double *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);
@@ -47,10 +47,10 @@ int day_tab[2][13] = {
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}};
char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
-"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
-"Thursday", "Friday", "Saturday", NULL};
+ "Thursday", "Friday", "Saturday", NULL};
/*****************************************************************************
@@ -71,7 +71,7 @@ char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
* the text field is not guaranteed to be NULL-terminated.
*/
static datetkn datetktbl[] = {
-/* text token lexval */
+/* text, token, lexval */
{EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
{"acsst", DTZ, 63}, /* Cent. Australia */
{"acst", TZ, 57}, /* Cent. Australia */
@@ -104,6 +104,7 @@ static datetkn datetktbl[] = {
{"cetdst", DTZ, 12}, /* Central European Dayl.Time */
{"cst", TZ, NEG(36)}, /* Central Standard Time */
{DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */
+ {"d", UNITS, DAY}, /* "day of month" for ISO input */
{"dec", MONTH, 12},
{"december", MONTH, 12},
{"dnt", TZ, 6}, /* Dansk Normal Tid */
@@ -124,6 +125,7 @@ static datetkn datetktbl[] = {
{"fwt", DTZ, 12}, /* French Winter Time */
{"gmt", TZ, 0}, /* Greenwish Mean Time */
{"gst", TZ, 60}, /* Guam Std Time, USSR Zone 9 */
+ {"h", UNITS, HOUR}, /* "hour" */
{"hdt", DTZ, NEG(54)}, /* Hawaii/Alaska */
{"hmt", DTZ, 18}, /* Hellas ? ? */
{"hst", TZ, NEG(60)}, /* Hawaii Std Time */
@@ -134,16 +136,19 @@ static datetkn datetktbl[] = {
/* "invalid" reserved for invalid time */
{"ist", TZ, 12}, /* Israel */
{"it", TZ, 21}, /* Iran Time */
+ {"j", UNITS, JULIAN},
{"jan", MONTH, 1},
{"january", MONTH, 1},
+ {"jd", UNITS, JULIAN},
{"jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */
{"jt", TZ, 45}, /* Java Time */
{"jul", MONTH, 7},
- {"july", MONTH, 7},
+ {"julian", UNITS, JULIAN},
{"jun", MONTH, 6},
{"june", MONTH, 6},
{"kst", TZ, 54}, /* Korea Standard Time */
{"ligt", TZ, 60}, /* From Melbourne, Australia */
+ {"m", UNITS, MONTH}, /* "month" for ISO input */
{"mar", MONTH, 3},
{"march", MONTH, 3},
{"may", MONTH, 5},
@@ -153,6 +158,7 @@ static datetkn datetktbl[] = {
{"metdst", DTZ, 12}, /* Middle Europe Daylight Time */
{"mewt", TZ, 6}, /* Middle Europe Winter Time */
{"mez", TZ, 6}, /* Middle Europe Zone */
+ {"mm", UNITS, MINUTE}, /* "minute" for ISO input */
{"mon", DOW, 1},
{"monday", DOW, 1},
{"mst", TZ, NEG(42)}, /* Mountain Standard Time */
@@ -174,6 +180,7 @@ static datetkn datetktbl[] = {
{"pdt", DTZ, NEG(42)}, /* Pacific Daylight Time */
{"pm", AMPM, PM},
{"pst", TZ, NEG(48)}, /* Pacific Standard Time */
+ {"s", UNITS, SECOND}, /* "seconds" for ISO input */
{"sadt", DTZ, 63}, /* S. Australian Dayl. Time */
{"sast", TZ, 57}, /* South Australian Std Time */
{"sat", DOW, 6},
@@ -186,6 +193,7 @@ static datetkn datetktbl[] = {
{"sun", DOW, 0},
{"sunday", DOW, 0},
{"swt", TZ, 6}, /* Swedish Winter Time */
+ {"t", DTK_ISO_TIME, 0}, /* Filler for ISO time fields */
{"thu", DOW, 4},
{"thur", DOW, 4},
{"thurs", DOW, 4},
@@ -208,6 +216,7 @@ static datetkn datetktbl[] = {
{"wet", TZ, 0}, /* Western Europe */
{"wetdst", DTZ, 6}, /* Western Europe */
{"wst", TZ, 48}, /* West Australian Std Time */
+ {"y", UNITS, YEAR}, /* "year" for ISO input */
{"ydt", DTZ, NEG(48)}, /* Yukon Daylight Time */
{YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
{"yst", TZ, NEG(54)}, /* Yukon Standard Time */
@@ -222,7 +231,7 @@ static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
/* Used for SET australian_timezones to override North American ones */
static datetkn australian_datetktbl[] = {
- {"cst", TZ, 63}, /* Australia Eastern Std Time */
+ {"cst", TZ, 63}, /* Australia Central Std Time */
{"est", TZ, 60}, /* Australia Eastern Std Time */
{"sat", TZ, 57},
};
@@ -231,7 +240,7 @@ static unsigned int australian_szdatetktbl = sizeof australian_datetktbl /
sizeof australian_datetktbl[0];
static datetkn deltatktbl[] = {
-/* text token lexval */
+/* text, token, lexval */
{"@", IGNORE, 0}, /* postgres relative time prefix */
{DAGO, AGO, 0}, /* "ago" indicates negative time offset */
{"c", UNITS, DTK_CENTURY}, /* "century" relative time units */
@@ -329,7 +338,8 @@ datetkn *deltacache[MAXDATEFIELDS] = {NULL};
* Use the algorithm by Henry Fliegel, a former NASA/JPL colleague
* now at Aerospace Corp. (hi, Henry!)
*
- * These routines will be used by other date/time packages - tgl 97/02/25
+ * These routines will be used by other date/time packages
+ * - thomas 97/02/25
*/
int
@@ -413,6 +423,7 @@ ParseDateTime(char *timestr, char *lowstr,
if (*cp == ':')
{
ftype[nf] = DTK_TIME;
+ *lp++ = *cp++;
while (isdigit((unsigned char) *cp) ||
(*cp == ':') || (*cp == '.'))
*lp++ = *cp++;
@@ -422,10 +433,20 @@ ParseDateTime(char *timestr, char *lowstr,
else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
{
ftype[nf] = DTK_DATE;
- while (isalnum((unsigned char) *cp) || (*cp == '-') ||
- (*cp == '/') || (*cp == '.'))
- *lp++ = tolower((unsigned char) *cp++);
-
+ *lp++ = *cp++;
+ /* second field is all digits? then no embedded text month */
+ if (isdigit((unsigned char) *cp))
+ {
+ while (isdigit((unsigned char) *cp) || (*cp == '-') ||
+ (*cp == '/') || (*cp == '.'))
+ *lp++ = *cp++;
+ }
+ else
+ {
+ while (isalnum((unsigned char) *cp) || (*cp == '-') ||
+ (*cp == '/') || (*cp == '.'))
+ *lp++ = tolower((unsigned char) *cp++);
+ }
}
/*
@@ -539,7 +560,7 @@ ParseDateTime(char *timestr, char *lowstr,
* Use the system-provided functions to get the current time zone
* if not specified in the input string.
* If the date is outside the time_t system-supported time range,
- * then assume GMT time zone. - tgl 97/05/27
+ * then assume GMT time zone. - thomas 1997/05/27
*/
int
DecodeDateTime(char **field, int *ftype, int nf,
@@ -548,6 +569,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
int fmask = 0,
tmask,
type;
+ int ptype = 0; /* "prefix type" for ISO y2001m02d04 format */
int i;
int flen,
val;
@@ -556,13 +578,16 @@ DecodeDateTime(char **field, int *ftype, int nf,
int is2digits = FALSE;
int bc = FALSE;
+ /* We'll insist on at least all of the date fields,
+ * but initialize the remaining fields in case they are not
+ * set later...
+ */
*dtype = DTK_DATE;
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
*fsec = 0;
- tm->tm_isdst = -1; /* don't know daylight savings time status
- * apriori */
+ tm->tm_isdst = -1; /* don't know daylight savings time status apriori */
if (tzp != NULL)
*tzp = 0;
@@ -571,13 +596,32 @@ DecodeDateTime(char **field, int *ftype, int nf,
switch (ftype[i])
{
case DTK_DATE:
+ /* Previous field was a label for "julian date"?
+ * then this should be a julian date with fractional day...
+ */
+ if (ptype == JULIAN)
+ {
+ char *cp;
+ double dt, date, time;
- /*
- * Already have a date? Then this might be a POSIX time
- * zone with an embedded dash (e.g. "PST-3" == "EST") -
- * thomas 2000-03-15
+ dt = strtod(field[i], &cp);
+ if (*cp != '\0')
+ return -1;
+
+ time = dt * 86400;
+ TMODULO(time, date, 86400e0);
+ j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+ dt2time(time, &tm->tm_hour, &tm->tm_min, fsec);
+
+ tmask = DTK_DATE_M | DTK_TIME_M;
+ *dtype = DTK_DATE;
+ }
+
+ /* Already have a date? Then this might be a POSIX time
+ * zone with an embedded dash (e.g. "PST-3" == "EST")
+ * - thomas 2000-03-15
*/
- if ((fmask & DTK_DATE_M) == DTK_DATE_M)
+ else if ((fmask & DTK_DATE_M) == DTK_DATE_M)
{
if ((tzp == NULL)
|| (DecodePosixTimezone(field[i], tzp) != 0))
@@ -587,15 +631,16 @@ DecodeDateTime(char **field, int *ftype, int nf,
tmask = DTK_M(TZ);
}
else if (DecodeDate(field[i], fmask, &tmask, tm) != 0)
+ {
return -1;
+ }
break;
case DTK_TIME:
if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
return -1;
- /*
- * check upper limit on hours; other limits checked in
+ /* Check upper limit on hours; other limits checked in
* DecodeTime()
*/
if (tm->tm_hour > 23)
@@ -618,7 +663,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
* PST)
*/
if ((i > 0) && ((fmask & DTK_M(TZ)) != 0)
- && (ftype[i - 1] == DTK_TZ) && (isalpha((unsigned char) *field[i - 1])))
+ && (ftype[i - 1] == DTK_TZ)
+ && (isalpha((unsigned char) *field[i - 1])))
{
*tzp -= tz;
tmask = 0;
@@ -634,21 +680,81 @@ DecodeDateTime(char **field, int *ftype, int nf,
case DTK_NUMBER:
flen = strlen(field[i]);
+ /* Was this an "ISO date" with embedded field labels?
+ * An example is "y2001m02d04" - thomas 2001-02-04
+ */
+ if (ptype != 0)
+ {
+ char *cp;
+ int val;
+
+ val = strtol(field[i], &cp, 10);
+ if (*cp != '\0')
+ return -1;
+
+ switch (ptype) {
+ case YEAR:
+ tm->tm_year = val;
+ tmask = DTK_M(ptype);
+ break;
+
+ case MONTH:
+ tm->tm_mon = val;
+ tmask = DTK_M(ptype);
+ break;
+
+ case DAY:
+ tm->tm_mday = val;
+ tmask = DTK_M(ptype);
+ break;
+
+ case HOUR:
+ tm->tm_hour = val;
+ tmask = DTK_M(ptype);
+ break;
+
+ case MINUTE:
+ tm->tm_min = val;
+ tmask = DTK_M(ptype);
+ break;
+
+ case SECOND:
+ tm->tm_sec = val;
+ tmask = DTK_M(ptype);
+ break;
+
+ case JULIAN:
+ /* previous field was a label for "julian date"?
+ * then this is a julian day with no fractional part
+ * (see DTK_DATE for cases involving fractional parts)
+ */
+ j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+
+ tmask = DTK_DATE_M;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ ptype = 0;
+ *dtype = DTK_DATE;
+ }
/*
* long numeric string and either no date or no time read
* yet? then interpret as a concatenated date or time...
*/
- if ((flen > 4) && !((fmask & DTK_DATE_M) && (fmask & DTK_TIME_M)))
+ else if ((flen > 4) && !((fmask & DTK_DATE_M) && (fmask & DTK_TIME_M)))
{
if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0)
return -1;
}
/* otherwise it is a single date/time field... */
- else
+ else if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0)
{
- if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0)
- return -1;
+ return -1;
}
break;
@@ -664,10 +770,15 @@ DecodeDateTime(char **field, int *ftype, int nf,
case RESERV:
switch (val)
{
+ case DTK_CURRENT:
case DTK_NOW:
tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
*dtype = DTK_DATE;
+#if NOT_USED
GetCurrentTime(tm);
+#else
+ GetCurrentTimeUsec(tm, fsec);
+#endif
if (tzp != NULL)
*tzp = CTimeZone;
break;
@@ -786,6 +897,18 @@ DecodeDateTime(char **field, int *ftype, int nf,
tm->tm_wday = val;
break;
+ case UNITS:
+ ptype = val;
+ tmask = 0;
+ break;
+
+ case DTK_ISO_TIME:
+ if ((i < 1) || (i >= (nf-1))
+ || (ftype[i-1] != DTK_DATE)
+ || (ftype[i+1] != DTK_TIME))
+ return -1;
+ break;
+
default:
return -1;
}
@@ -1182,6 +1305,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
str++;
}
+ /* Just get rid of any non-digit, non-alpha characters... */
if (*str != '\0')
*str++ = '\0';
nf++;
@@ -1362,8 +1486,9 @@ DecodeNumber(int flen, char *str, int fmask,
/*
* Enough digits to be unequivocal year? Used to test for 4 digits or
* more, but we now test first for a three-digit doy so anything
- * bigger than two digits had better be an explicit year. - thomas
- * 1999-01-09 Back to requiring a 4 digit year. We accept a two digit
+ * bigger than two digits had better be an explicit year.
+ * - thomas 1999-01-09
+ * Back to requiring a 4 digit year. We accept a two digit
* year farther down. - thomas 2000-03-28
*/
else if (flen >= 4)
@@ -1613,7 +1738,7 @@ DecodeSpecial(int field, char *lowtoken, int *val)
datecache[field] = tp;
if (tp == NULL)
{
- type = IGNORE;
+ type = UNKNOWN_FIELD;
*val = 0;
}
else
@@ -1747,10 +1872,11 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
case DTK_NUMBER:
val = strtol(field[i], &cp, 10);
+ if (type == IGNORE)
+ type = DTK_SECOND;
+
if (*cp == '.')
{
- if (type == IGNORE)
- type = DTK_SECOND;
fval = strtod(cp, &cp);
if (*cp != '\0')
return -1;
@@ -1928,7 +2054,7 @@ DecodeUnits(int field, char *lowtoken, int *val)
deltacache[field] = tp;
if (tp == NULL)
{
- type = IGNORE;
+ type = UNKNOWN_FIELD;
*val = 0;
}
else
@@ -1985,8 +2111,8 @@ EncodeDateOnly(struct tm * tm, int style, char *str)
switch (style)
{
- /* compatible with ISO date formats */
case USE_ISO_DATES:
+ /* compatible with ISO date formats */
if (tm->tm_year > 0)
sprintf(str, "%04d-%02d-%02d",
tm->tm_year, tm->tm_mon, tm->tm_mday);
@@ -1995,8 +2121,8 @@ EncodeDateOnly(struct tm * tm, int style, char *str)
-(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
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
@@ -2007,8 +2133,8 @@ EncodeDateOnly(struct tm * tm, int style, char *str)
sprintf((str + 5), "/%04d %s", -(tm->tm_year - 1), "BC");
break;
- /* German-style date format */
case USE_GERMAN_DATES:
+ /* German-style date format */
sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
if (tm->tm_year > 0)
sprintf((str + 5), ".%04d", tm->tm_year);
@@ -2016,9 +2142,9 @@ EncodeDateOnly(struct tm * tm, int style, char *str)
sprintf((str + 5), ".%04d %s", -(tm->tm_year - 1), "BC");
break;
- /* traditional date-only style for Postgres */
case USE_POSTGRES_DATES:
default:
+ /* traditional date-only style for Postgres */
if (EuroDates)
sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
else
diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c
index 59b516556c9..c80b5c429b6 100644
--- a/src/backend/utils/adt/format_type.c
+++ b/src/backend/utils/adt/format_type.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.15 2001/09/21 15:27:38 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.16 2001/09/28 08:09:10 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -205,6 +205,10 @@ format_type_internal(Oid type_oid, int32 typemod, bool allow_invalid)
break;
case TIMESTAMPOID:
+ buf = pstrdup("timestamp without time zone");
+ break;
+
+ case TIMESTAMPTZOID:
buf = pstrdup("timestamp with time zone");
break;
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 532f3eb1d49..d517eb68183 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.40 2001/09/12 04:01:57 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.41 2001/09/28 08:09:11 thomas Exp $
*
*
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
@@ -2753,6 +2753,30 @@ timestamp_to_char(PG_FUNCTION_ARGS)
Timestamp dt = PG_GETARG_TIMESTAMP(0);
text *fmt = PG_GETARG_TEXT_P(1), *res;
TmToChar tmtc;
+ int r = 0;
+
+ if ((VARSIZE(fmt) - VARHDRSZ) <=0 || TIMESTAMP_NOT_FINITE(dt))
+ PG_RETURN_NULL();
+
+ ZERO_tmtc(&tmtc);
+
+ r = timestamp2tm(dt, NULL, tmtcTm(&tmtc), &tmtcFsec(&tmtc), NULL);
+
+ if (r != 0)
+ elog(ERROR, "to_char(): Unable to convert timestamp to tm");
+
+ if (!(res=datetime_to_char_body(&tmtc, fmt)))
+ PG_RETURN_NULL();
+
+ PG_RETURN_TEXT_P(res);
+}
+
+Datum
+timestamptz_to_char(PG_FUNCTION_ARGS)
+{
+ TimestampTz dt = PG_GETARG_TIMESTAMP(0);
+ text *fmt = PG_GETARG_TEXT_P(1), *res;
+ TmToChar tmtc;
int tz, r = 0;
if ((VARSIZE(fmt) - VARHDRSZ) <=0 || TIMESTAMP_NOT_FINITE(dt))
@@ -2760,12 +2784,7 @@ timestamp_to_char(PG_FUNCTION_ARGS)
ZERO_tmtc(&tmtc);
- if (TIMESTAMP_IS_EPOCH(dt))
- r = timestamp2tm(SetTimestamp(dt), NULL, tmtcTm(&tmtc), &tmtcFsec(&tmtc), NULL);
- else if (TIMESTAMP_IS_CURRENT(dt))
- r = timestamp2tm(SetTimestamp(dt), &tz, tmtcTm(&tmtc), &tmtcFsec(&tmtc), &tmtcTzn(&tmtc));
- else
- r = timestamp2tm(dt, &tz, tmtcTm(&tmtc), &tmtcFsec(&tmtc), &tmtcTzn(&tmtc));
+ r = timestamp2tm(dt, &tz, tmtcTm(&tmtc), &tmtcFsec(&tmtc), &tmtcTzn(&tmtc));
if (r != 0)
elog(ERROR, "to_char(): Unable to convert timestamp to tm");
@@ -2805,7 +2824,7 @@ interval_to_char(PG_FUNCTION_ARGS)
/* ---------------------
* TO_TIMESTAMP()
*
- * Make Timestamp from date_str which is formated at argument 'fmt'
+ * Make Timestamp from date_str which is formatted at argument 'fmt'
* ( to_timestamp is reverse to_char() )
* ---------------------
*/
diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c
index 0f8ed87e5ba..ca8d728454b 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.85 2001/05/03 19:00:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.86 2001/09/28 08:09:11 thomas Exp $
*
* NOTES
*
@@ -179,6 +179,84 @@ GetCurrentAbsoluteTime(void)
} /* GetCurrentAbsoluteTime() */
+/* GetCurrentAbsoluteTime()
+ * Get the current system time. Set timezone parameters if not specified elsewhere.
+ * Define HasTZSet to allow clients to specify the default timezone.
+ *
+ * Returns the number of seconds since epoch (January 1 1970 GMT)
+ */
+AbsoluteTime
+GetCurrentAbsoluteTimeUsec(int *usec)
+{
+ time_t now;
+ struct timeval tp;
+// struct timezone tpz;
+#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
+ struct tm *tm;
+#else
+ struct timeb tb; /* the old V7-ism */
+#endif
+
+ gettimeofday(&tp, NULL);
+
+ now = tp.tv_sec;
+ *usec = tp.tv_usec;
+
+#ifdef NOT_USED
+#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
+ now = time(NULL);
+#else
+ ftime(&tb);
+ now = tb.time;
+#endif
+#endif
+
+ if (!HasCTZSet)
+ {
+#if defined(HAVE_TM_ZONE)
+ tm = localtime(&now);
+
+ CTimeZone = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
+ CDayLight = (tm->tm_isdst > 0);
+
+#ifdef NOT_USED
+
+ /*
+ * XXX is there a better way to get local timezone string w/o
+ * tzname? - tgl 97/03/18
+ */
+ strftime(CTZName, MAXTZLEN, "%Z", tm);
+#endif
+
+ /*
+ * XXX FreeBSD man pages indicate that this should work - thomas
+ * 1998-12-12
+ */
+ strcpy(CTZName, tm->tm_zone);
+
+#elif defined(HAVE_INT_TIMEZONE)
+ tm = localtime(&now);
+
+ CDayLight = tm->tm_isdst;
+ CTimeZone = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
+ strcpy(CTZName, tzname[tm->tm_isdst]);
+#else /* neither HAVE_TM_ZONE nor
+ * HAVE_INT_TIMEZONE */
+ CTimeZone = tb.timezone * 60;
+ CDayLight = (tb.dstflag != 0);
+
+ /*
+ * XXX does this work to get the local timezone string in V7? -
+ * tgl 97/03/18
+ */
+ strftime(CTZName, MAXTZLEN, "%Z", localtime(&now));
+#endif
+ };
+
+ return (AbsoluteTime) now;
+} /* GetCurrentAbsoluteTime() */
+
+
void
GetCurrentTime(struct tm * tm)
{
@@ -191,6 +269,19 @@ GetCurrentTime(struct tm * tm)
void
+GetCurrentTimeUsec(struct tm *tm, double *fsec)
+{
+ int tz;
+ int usec;
+
+ abstime2tm(GetCurrentTransactionStartTimeUsec(&usec), &tz, tm, NULL);
+ *fsec = usec * 1.0e-6;
+
+ return;
+} /* GetCurrentTimeUsec() */
+
+
+void
abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char *tzn)
{
time_t time = (time_t) _time;
@@ -357,11 +448,9 @@ nabstimein(PG_FUNCTION_ARGS)
break;
case DTK_EPOCH:
- result = EPOCH_ABSTIME;
- break;
-
- case DTK_CURRENT:
- result = CURRENT_ABSTIME;
+ /* Don't bother retaining this as a reserved value,
+ * but instead just set to the actual epoch time (1970-01-01) */
+ result = 0;
break;
case DTK_LATE:
@@ -404,15 +493,12 @@ nabstimeout(PG_FUNCTION_ARGS)
switch (time)
{
- case EPOCH_ABSTIME:
- strcpy(buf, EPOCH);
- break;
+ /* Note that timestamp no longer supports 'invalid'.
+ * Retain 'invalid' for abstime for now, but dump it someday.
+ */
case INVALID_ABSTIME:
strcpy(buf, INVALID);
break;
- case CURRENT_ABSTIME:
- strcpy(buf, DCURRENT);
- break;
case NOEND_ABSTIME:
strcpy(buf, LATE);
break;
@@ -449,37 +535,37 @@ abstime_finite(PG_FUNCTION_ARGS)
static int
abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
{
- /*
- * We consider all INVALIDs to be equal and larger than any non-INVALID.
- * This is somewhat arbitrary; the important thing is to have a
- * consistent sort order.
- */
+/*
+ * We consider all INVALIDs to be equal and larger than any non-INVALID.
+ * This is somewhat arbitrary; the important thing is to have a
+ * consistent sort order.
+ */
if (a == INVALID_ABSTIME)
{
- if (b == INVALID_ABSTIME)
- return 0; /* INVALID = INVALID */
- else
- return 1; /* INVALID > non-INVALID */
- }
- else if (b == INVALID_ABSTIME)
- {
- return -1; /* non-INVALID < INVALID */
+ if (b == INVALID_ABSTIME)
+ return 0; /* INVALID = INVALID */
+ else
+ return 1; /* INVALID > non-INVALID */
}
+
+ if (b == INVALID_ABSTIME)
+ return -1; /* non-INVALID < INVALID */
+
+#if 0
+/* CURRENT is no longer stored internally... */
+ /* XXX this is broken, should go away: */
+ if (a == CURRENT_ABSTIME)
+ a = GetCurrentTransactionStartTime();
+ if (b == CURRENT_ABSTIME)
+ b = GetCurrentTransactionStartTime();
+#endif
+
+ if (a > b)
+ return 1;
+ else if (a == b)
+ return 0;
else
- {
- /* XXX this is broken, should go away: */
- if (a == CURRENT_ABSTIME)
- a = GetCurrentTransactionStartTime();
- if (b == CURRENT_ABSTIME)
- b = GetCurrentTransactionStartTime();
-
- if (a > b)
- return 1;
- else if (a == b)
- return 0;
- else
- return -1;
- }
+ return -1;
}
Datum
@@ -546,7 +632,7 @@ btabstimecmp(PG_FUNCTION_ARGS)
}
-/* datetime_abstime()
+/* timestamp_abstime()
* Convert timestamp to abstime.
*/
Datum
@@ -555,26 +641,23 @@ timestamp_abstime(PG_FUNCTION_ARGS)
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
AbsoluteTime result;
double fsec;
+ int tz;
struct tm tt,
*tm = &tt;
- if (TIMESTAMP_IS_INVALID(timestamp))
- result = INVALID_ABSTIME;
- else if (TIMESTAMP_IS_NOBEGIN(timestamp))
+ if (TIMESTAMP_IS_NOBEGIN(timestamp))
result = NOSTART_ABSTIME;
else if (TIMESTAMP_IS_NOEND(timestamp))
result = NOEND_ABSTIME;
+ else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
+ {
+ tz = DetermineLocalTimeZone(tm);
+ result = tm2abstime(tm, tz);
+ }
else
{
- if (TIMESTAMP_IS_RELATIVE(timestamp))
- {
- timestamp2tm(SetTimestamp(timestamp), NULL, tm, &fsec, NULL);
- result = tm2abstime(tm, 0);
- }
- else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
- result = tm2abstime(tm, 0);
- else
- result = INVALID_ABSTIME;
+ elog(ERROR, "Unable to convert timestamp to abstime");
+ result = INVALID_ABSTIME;
}
PG_RETURN_ABSOLUTETIME(result);
@@ -588,11 +671,16 @@ abstime_timestamp(PG_FUNCTION_ARGS)
{
AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
Timestamp result;
+ struct tm tt,
+ *tm = &tt;
+ int tz;
+ char tzn[MAXTZLEN];
switch (abstime)
{
case INVALID_ABSTIME:
- TIMESTAMP_INVALID(result);
+ elog(ERROR, "Unable to convert abstime 'invalid' to timestamp");
+ TIMESTAMP_NOBEGIN(result);
break;
case NOSTART_ABSTIME:
@@ -603,12 +691,65 @@ abstime_timestamp(PG_FUNCTION_ARGS)
TIMESTAMP_NOEND(result);
break;
- case EPOCH_ABSTIME:
- TIMESTAMP_EPOCH(result);
+ default:
+ abstime2tm(abstime, &tz, tm, tzn);
+ result = abstime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400) + tz;
break;
+ };
+
+ PG_RETURN_TIMESTAMP(result);
+}
+
+
+/* timestamptz_abstime()
+ * Convert timestamp with time zone to abstime.
+ */
+Datum
+timestamptz_abstime(PG_FUNCTION_ARGS)
+{
+ TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
+ AbsoluteTime result;
+ double fsec;
+ struct tm tt,
+ *tm = &tt;
- case CURRENT_ABSTIME:
- TIMESTAMP_CURRENT(result);
+ if (TIMESTAMP_IS_NOBEGIN(timestamp))
+ result = NOSTART_ABSTIME;
+ else if (TIMESTAMP_IS_NOEND(timestamp))
+ result = NOEND_ABSTIME;
+ else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
+ result = tm2abstime(tm, 0);
+ else
+ {
+ elog(ERROR, "Unable to convert timestamp to abstime");
+ result = INVALID_ABSTIME;
+ }
+
+ PG_RETURN_ABSOLUTETIME(result);
+}
+
+/* abstime_timestamptz()
+ * Convert abstime to timestamp.
+ */
+Datum
+abstime_timestamptz(PG_FUNCTION_ARGS)
+{
+ AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
+ TimestampTz result;
+
+ switch (abstime)
+ {
+ case INVALID_ABSTIME:
+ elog(ERROR, "Unable to convert abstime 'invalid' to timestamptz");
+ TIMESTAMP_NOBEGIN(result);
+ break;
+
+ case NOSTART_ABSTIME:
+ TIMESTAMP_NOBEGIN(result);
+ break;
+
+ case NOEND_ABSTIME:
+ TIMESTAMP_NOEND(result);
break;
default:
@@ -653,14 +794,15 @@ reltimein(PG_FUNCTION_ARGS)
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));
- PG_RETURN_RELATIVETIME(result);
+ break;
default:
- PG_RETURN_RELATIVETIME(INVALID_RELTIME);
+ elog(ERROR, "Bad reltime (internal coding error) '%s'", str);
+ result = INVALID_RELTIME;
+ break;
}
- elog(ERROR, "Bad reltime (internal coding error) '%s'", str);
- PG_RETURN_RELATIVETIME(INVALID_RELTIME);
+ PG_RETURN_RELATIVETIME(result);
}
@@ -676,13 +818,8 @@ reltimeout(PG_FUNCTION_ARGS)
*tm = &tt;
char buf[MAXDATELEN + 1];
- if (time == INVALID_RELTIME)
- strcpy(buf, INVALID_RELTIME_STR);
- else
- {
- reltime2tm(time, tm);
- EncodeTimeSpan(tm, 0, DateStyle, buf);
- }
+ reltime2tm(time, tm);
+ EncodeTimeSpan(tm, 0, DateStyle, buf);
result = pstrdup(buf);
PG_RETURN_CSTRING(result);
@@ -702,44 +839,6 @@ reltime2tm(RelativeTime time, struct tm * tm)
return;
} /* reltime2tm() */
-#ifdef NOT_USED
-int
-dummyfunc()
-{
- char *timestring;
- long quantity;
- int i;
- int unitnr;
-
- timestring = (char *) palloc(Max(strlen(INVALID_RELTIME_STR),
- UNITMAXLEN) + 1);
- if (timevalue == INVALID_RELTIME)
- {
- strcpy(timestring, INVALID_RELTIME_STR);
- return timestring;
- }
-
- if (timevalue == 0)
- i = 1; /* unit = 'seconds' */
- else
- for (i = 12; i >= 0; i = i - 2)
- if ((timevalue % sec_tab[i]) == 0)
- break; /* appropriate unit found */
- unitnr = i;
- quantity = (timevalue / sec_tab[unitnr]);
- if (quantity > 1 || quantity < -1)
- unitnr++; /* adjust index for PLURAL of unit */
- if (quantity >= 0)
- sprintf(timestring, "%c %lu %s", RELTIME_LABEL,
- quantity, unit_tab[unitnr]);
- else
- sprintf(timestring, "%c %lu %s %s", RELTIME_LABEL,
- (quantity * -1), unit_tab[unitnr], RELTIME_PAST);
- return timestring;
-}
-
-#endif
-
/*
* tintervalin - converts an interval string to internal format
@@ -749,26 +848,25 @@ tintervalin(PG_FUNCTION_ARGS)
{
char *intervalstr = PG_GETARG_CSTRING(0);
TimeInterval interval;
- int error;
AbsoluteTime i_start,
i_end,
t1,
t2;
interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
- error = istinterval(intervalstr, &t1, &t2);
- if (error == 0)
- interval->status = T_INTERVAL_INVAL;
+ if (istinterval(intervalstr, &t1, &t2) == 0)
+ elog(ERROR, "Unable to decode tinterval '%s'", intervalstr);
+
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- interval->status = T_INTERVAL_INVAL; /* undefined */
+ interval->status = T_INTERVAL_INVAL; /* undefined */
else
- {
- i_start = ABSTIMEMIN(t1, t2);
- i_end = ABSTIMEMAX(t1, t2);
- interval->data[0] = i_start;
- interval->data[1] = i_end;
interval->status = T_INTERVAL_VALID;
- }
+
+ i_start = ABSTIMEMIN(t1, t2);
+ i_end = ABSTIMEMAX(t1, t2);
+ interval->data[0] = i_start;
+ interval->data[1] = i_end;
+
PG_RETURN_TIMEINTERVAL(interval);
}
@@ -818,30 +916,28 @@ interval_reltime(PG_FUNCTION_ARGS)
month;
double span;
- if (INTERVAL_IS_INVALID(*interval))
- time = INVALID_RELTIME;
+ if (interval->month == 0)
+ {
+ year = 0;
+ month = 0;
+ }
+ else if (abs(interval->month) >= 12)
+ {
+ year = (interval->month / 12);
+ month = (interval->month % 12);
+ }
else
{
- if (interval->month == 0)
- {
- year = 0;
- month = 0;
- }
- else if (abs(interval->month) >= 12)
- {
- year = (interval->month / 12);
- month = (interval->month % 12);
- }
- else
- {
- year = 0;
- month = interval->month;
- }
+ year = 0;
+ month = interval->month;
+ }
- span = (((((double) 365 * year) + ((double) 30 * month)) * 86400) + interval->time);
+ span = (((((double) 365 * year) + ((double) 30 * month)) * 86400) + interval->time);
- time = (((span > INT_MIN) && (span < INT_MAX)) ? span : INVALID_RELTIME);
- }
+ if ((span < INT_MIN) || (span > INT_MAX))
+ time = INVALID_RELTIME;
+ else
+ time = span;
PG_RETURN_RELATIVETIME(time);
}
@@ -860,7 +956,9 @@ reltime_interval(PG_FUNCTION_ARGS)
switch (reltime)
{
case INVALID_RELTIME:
- INTERVAL_INVALID(*result);
+ elog(ERROR, "Unable to convert reltime 'invalid' to interval");
+ result->time = 0;
+ result->month = 0;
break;
default:
@@ -884,11 +982,12 @@ mktinterval(PG_FUNCTION_ARGS)
{
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
- AbsoluteTime tstart = ABSTIMEMIN(t1, t2),
- tend = ABSTIMEMAX(t1, t2);
+ AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
+ AbsoluteTime tend = ABSTIMEMAX(t1, t2);
TimeInterval interval;
interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
+
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
interval->status = T_INTERVAL_INVAL;
else
@@ -909,7 +1008,7 @@ mktinterval(PG_FUNCTION_ARGS)
*/
/*
- * timepl - returns the value of (abstime t1 + relime t2)
+ * timepl - returns the value of (abstime t1 + reltime t2)
*/
Datum
timepl(PG_FUNCTION_ARGS)
@@ -917,8 +1016,10 @@ 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) &&
@@ -939,8 +1040,10 @@ 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) &&
@@ -953,27 +1056,6 @@ timemi(PG_FUNCTION_ARGS)
/*
- * abstimemi - returns the value of (abstime t1 - abstime t2)
- *
- * This is not exported, so it's not been made fmgr-compatible.
- */
-static RelativeTime
-abstimemi(AbsoluteTime t1, AbsoluteTime t2)
-{
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- if (AbsoluteTimeIsReal(t1) &&
- AbsoluteTimeIsReal(t2))
- return t1 - t2;
-
- return INVALID_RELTIME;
-}
-
-
-/*
* intinterval - returns true iff absolute date is in the interval
*/
Datum
@@ -1002,13 +1084,20 @@ Datum
tintervalrel(PG_FUNCTION_ARGS)
{
TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
+ AbsoluteTime t1 = interval->data[0];
+ AbsoluteTime t2 = interval->data[1];
if (interval->status != T_INTERVAL_VALID)
PG_RETURN_RELATIVETIME(INVALID_RELTIME);
- PG_RETURN_RELATIVETIME(abstimemi(interval->data[1], interval->data[0]));
+ if (AbsoluteTimeIsReal(t1) &&
+ AbsoluteTimeIsReal(t2))
+ PG_RETURN_RELATIVETIME(t2 - t1);
+
+ PG_RETURN_RELATIVETIME(INVALID_RELTIME);
}
+
/*
* timenow - returns time "now", internal format
*
@@ -1021,6 +1110,7 @@ timenow(PG_FUNCTION_ARGS)
if (time(&sec) < 0)
PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
+
PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
}
@@ -1113,11 +1203,11 @@ tintervalsame(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false);
if (DatumGetBool(DirectFunctionCall2(abstimeeq,
- AbsoluteTimeGetDatum(i1->data[0]),
- AbsoluteTimeGetDatum(i2->data[0]))) &&
+ AbsoluteTimeGetDatum(i1->data[0]),
+ AbsoluteTimeGetDatum(i2->data[0]))) &&
DatumGetBool(DirectFunctionCall2(abstimeeq,
- AbsoluteTimeGetDatum(i1->data[1]),
- AbsoluteTimeGetDatum(i2->data[1]))))
+ AbsoluteTimeGetDatum(i1->data[1]),
+ AbsoluteTimeGetDatum(i2->data[1]))))
PG_RETURN_BOOL(true);
PG_RETURN_BOOL(false);
}
@@ -1133,9 +1223,9 @@ tintervaleq(PG_FUNCTION_ARGS)
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
AbsoluteTime t10,
- t11,
- t20,
- t21;
+ t11,
+ t20,
+ t21;
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
PG_RETURN_BOOL(false);
@@ -1145,19 +1235,10 @@ tintervaleq(PG_FUNCTION_ARGS)
t20 = i2->data[0];
t21 = i2->data[1];
- if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
+ if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
PG_RETURN_BOOL(false);
- if (t10 == CURRENT_ABSTIME)
- t10 = GetCurrentTransactionStartTime();
- if (t11 == CURRENT_ABSTIME)
- t11 = GetCurrentTransactionStartTime();
- if (t20 == CURRENT_ABSTIME)
- t20 = GetCurrentTransactionStartTime();
- if (t21 == CURRENT_ABSTIME)
- t21 = GetCurrentTransactionStartTime();
-
PG_RETURN_BOOL((t11 - t10) == (t21 - t20));
}
@@ -1167,9 +1248,9 @@ tintervalne(PG_FUNCTION_ARGS)
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
AbsoluteTime t10,
- t11,
- t20,
- t21;
+ t11,
+ t20,
+ t21;
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
PG_RETURN_BOOL(false);
@@ -1179,19 +1260,10 @@ tintervalne(PG_FUNCTION_ARGS)
t20 = i2->data[0];
t21 = i2->data[1];
- if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
+ if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
PG_RETURN_BOOL(false);
- if (t10 == CURRENT_ABSTIME)
- t10 = GetCurrentTransactionStartTime();
- if (t11 == CURRENT_ABSTIME)
- t11 = GetCurrentTransactionStartTime();
- if (t20 == CURRENT_ABSTIME)
- t20 = GetCurrentTransactionStartTime();
- if (t21 == CURRENT_ABSTIME)
- t21 = GetCurrentTransactionStartTime();
-
PG_RETURN_BOOL((t11 - t10) != (t21 - t20));
}
@@ -1201,9 +1273,9 @@ tintervallt(PG_FUNCTION_ARGS)
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
AbsoluteTime t10,
- t11,
- t20,
- t21;
+ t11,
+ t20,
+ t21;
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
PG_RETURN_BOOL(false);
@@ -1213,19 +1285,10 @@ tintervallt(PG_FUNCTION_ARGS)
t20 = i2->data[0];
t21 = i2->data[1];
- if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
+ if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
PG_RETURN_BOOL(false);
- if (t10 == CURRENT_ABSTIME)
- t10 = GetCurrentTransactionStartTime();
- if (t11 == CURRENT_ABSTIME)
- t11 = GetCurrentTransactionStartTime();
- if (t20 == CURRENT_ABSTIME)
- t20 = GetCurrentTransactionStartTime();
- if (t21 == CURRENT_ABSTIME)
- t21 = GetCurrentTransactionStartTime();
-
PG_RETURN_BOOL((t11 - t10) < (t21 - t20));
}
@@ -1235,9 +1298,9 @@ tintervalle(PG_FUNCTION_ARGS)
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
AbsoluteTime t10,
- t11,
- t20,
- t21;
+ t11,
+ t20,
+ t21;
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
PG_RETURN_BOOL(false);
@@ -1247,19 +1310,10 @@ tintervalle(PG_FUNCTION_ARGS)
t20 = i2->data[0];
t21 = i2->data[1];
- if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
+ if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
PG_RETURN_BOOL(false);
- if (t10 == CURRENT_ABSTIME)
- t10 = GetCurrentTransactionStartTime();
- if (t11 == CURRENT_ABSTIME)
- t11 = GetCurrentTransactionStartTime();
- if (t20 == CURRENT_ABSTIME)
- t20 = GetCurrentTransactionStartTime();
- if (t21 == CURRENT_ABSTIME)
- t21 = GetCurrentTransactionStartTime();
-
PG_RETURN_BOOL((t11 - t10) <= (t21 - t20));
}
@@ -1281,19 +1335,10 @@ tintervalgt(PG_FUNCTION_ARGS)
t20 = i2->data[0];
t21 = i2->data[1];
- if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
+ if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
PG_RETURN_BOOL(false);
- if (t10 == CURRENT_ABSTIME)
- t10 = GetCurrentTransactionStartTime();
- if (t11 == CURRENT_ABSTIME)
- t11 = GetCurrentTransactionStartTime();
- if (t20 == CURRENT_ABSTIME)
- t20 = GetCurrentTransactionStartTime();
- if (t21 == CURRENT_ABSTIME)
- t21 = GetCurrentTransactionStartTime();
-
PG_RETURN_BOOL((t11 - t10) > (t21 - t20));
}
@@ -1315,19 +1360,10 @@ tintervalge(PG_FUNCTION_ARGS)
t20 = i2->data[0];
t21 = i2->data[1];
- if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
+ if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
PG_RETURN_BOOL(false);
- if (t10 == CURRENT_ABSTIME)
- t10 = GetCurrentTransactionStartTime();
- if (t11 == CURRENT_ABSTIME)
- t11 = GetCurrentTransactionStartTime();
- if (t20 == CURRENT_ABSTIME)
- t20 = GetCurrentTransactionStartTime();
- if (t21 == CURRENT_ABSTIME)
- t21 = GetCurrentTransactionStartTime();
-
PG_RETURN_BOOL((t11 - t10) >= (t21 - t20));
}
@@ -1356,8 +1392,8 @@ tintervalleneq(PG_FUNCTION_ARGS)
if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
PG_RETURN_BOOL(false);
rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
- TimeIntervalGetDatum(i)));
- PG_RETURN_BOOL(rt != INVALID_RELTIME && rt == t);
+ TimeIntervalGetDatum(i)));
+ PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt == t));
}
Datum
@@ -1371,7 +1407,7 @@ tintervallenne(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false);
rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
TimeIntervalGetDatum(i)));
- PG_RETURN_BOOL(rt != INVALID_RELTIME && rt != t);
+ PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt != t));
}
Datum
@@ -1385,7 +1421,7 @@ tintervallenlt(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false);
rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
TimeIntervalGetDatum(i)));
- PG_RETURN_BOOL(rt != INVALID_RELTIME && rt < t);
+ PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt < t));
}
Datum
@@ -1399,7 +1435,7 @@ tintervallengt(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false);
rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
TimeIntervalGetDatum(i)));
- PG_RETURN_BOOL(rt != INVALID_RELTIME && rt > t);
+ PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt > t));
}
Datum
@@ -1413,7 +1449,7 @@ tintervallenle(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false);
rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
TimeIntervalGetDatum(i)));
- PG_RETURN_BOOL(rt != INVALID_RELTIME && rt <= t);
+ PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt <= t));
}
Datum
@@ -1427,7 +1463,7 @@ tintervallenge(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false);
rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
TimeIntervalGetDatum(i)));
- PG_RETURN_BOOL(rt != INVALID_RELTIME && rt >= t);
+ PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt >= t));
}
/*
@@ -1463,11 +1499,11 @@ tintervalov(PG_FUNCTION_ARGS)
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
PG_RETURN_BOOL(false);
if (DatumGetBool(DirectFunctionCall2(abstimelt,
- AbsoluteTimeGetDatum(i1->data[1]),
- AbsoluteTimeGetDatum(i2->data[0]))) ||
+ AbsoluteTimeGetDatum(i1->data[1]),
+ AbsoluteTimeGetDatum(i2->data[0]))) ||
DatumGetBool(DirectFunctionCall2(abstimegt,
- AbsoluteTimeGetDatum(i1->data[0]),
- AbsoluteTimeGetDatum(i2->data[1]))))
+ AbsoluteTimeGetDatum(i1->data[0]),
+ AbsoluteTimeGetDatum(i2->data[1]))))
PG_RETURN_BOOL(false);
PG_RETURN_BOOL(true);
}
@@ -1503,222 +1539,6 @@ tintervalend(PG_FUNCTION_ARGS)
* PRIVATE ROUTINES *
*****************************************************************************/
-#ifdef NOT_USED
-/*
- * isreltime - returns 1, iff datestring is of type reltime
- * 2, iff datestring is 'invalid time' identifier
- * 0, iff datestring contains a syntax error
- * VALID time less or equal +/- `@ 68 years'
- *
- */
-int
-isreltime(char *str)
-{
- struct tm tt,
- *tm = &tt;
- double fsec;
- int dtype;
- char *field[MAXDATEFIELDS];
- int nf,
- ftype[MAXDATEFIELDS];
- char lowstr[MAXDATELEN + 1];
-
- if (!PointerIsValid(str))
- return 0;
-
- if (strlen(str) > MAXDATELEN)
- return 0;
-
- if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
- || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
- return 0;
-
- switch (dtype)
- {
- case (DTK_DELTA):
- return (abs(tm->tm_year) <= 68) ? 1 : 0;
- break;
-
- case (DTK_INVALID):
- return 2;
- break;
-
- default:
- return 0;
- break;
- }
-
- return 0;
-} /* isreltime() */
-
-#endif
-
-#ifdef NOT_USED
-int
-dummyfunc()
-{
- char *p;
- char c;
- int i;
- char unit[UNITMAXLEN];
- char direction[DIRMAXLEN];
- int localSign;
- int localUnitNumber;
- long localQuantity;
-
- if (!PointerIsValid(sign))
- sign = &localSign;
-
- if (!PointerIsValid(unitnr))
- unitnr = &localUnitNumber;
-
- if (!PointerIsValid(quantity))
- quantity = &localQuantity;
-
- unit[0] = '\0';
- direction[0] = '\0';
- p = timestring;
- /* skip leading blanks */
- while ((c = *p) != '\0')
- {
- if (c != ' ')
- break;
- p++;
- }
-
- /* Test whether 'invalid time' identifier or not */
- if (!strncmp(INVALID_RELTIME_STR, p, strlen(INVALID_RELTIME_STR) + 1))
- return 2; /* correct 'invalid time' identifier found */
-
- /* handle label of relative time */
- if (c != RELTIME_LABEL)
- return 0; /* syntax error */
- c = *++p;
- if (c != ' ')
- return 0; /* syntax error */
- p++;
- /* handle the quantity */
- *quantity = 0;
- for (;;)
- {
- c = *p;
- if (isdigit((unsigned char) c))
- {
- *quantity = *quantity * 10 + (c - '0');
- p++;
- }
- else
- {
- if (c == ' ')
- break; /* correct quantity found */
- else
- return 0; /* syntax error */
- }
- }
-
- /* handle unit */
- p++;
- i = 0;
- for (;;)
- {
- c = *p;
- if (c >= 'a' && c <= 'z' && i <= (UNITMAXLEN - 1))
- {
- unit[i] = c;
- p++;
- i++;
- }
- else
- {
- if ((c == ' ' || c == '\0')
- && correct_unit(unit, unitnr))
- break; /* correct unit found */
- else
- return 0; /* syntax error */
- }
- }
-
- /* handle optional direction */
- if (c == ' ')
- p++;
- i = 0;
- *sign = 1;
- for (;;)
- {
- c = *p;
- if (c >= 'a' && c <= 'z' && i <= (DIRMAXLEN - 1))
- {
- direction[i] = c;
- p++;
- i++;
- }
- else
- {
- if ((c == ' ' || c == '\0') && i == 0)
- {
- *sign = 1;
- break; /* no direction specified */
- }
- if ((c == ' ' || c == '\0') && i != 0)
- {
- direction[i] = '\0';
- correct_dir(direction, sign);
- break; /* correct direction found */
- }
- else
- return 0; /* syntax error */
- }
- }
-
- return 1;
-}
-
-/*
- * correct_unit - returns 1, iff unit is a correct unit description
- *
- * output parameter:
- * unptr: points to an integer which is the appropriate unit number
- * (see function isreltime())
- */
-static int
-correct_unit(char *unit, int *unptr)
-{
- int j = 0;
-
- while (j < NUNITS)
- {
- if (strncmp(unit, unit_tab[j], strlen(unit_tab[j])) == 0)
- {
- *unptr = j;
- return 1;
- }
- j++;
- }
- return 0; /* invalid unit descriptor */
-}
-
-/*
- * correct_dir - returns 1, iff direction is a correct identifier
- *
- * output parameter:
- * signptr: points to -1 if dir corresponds to past tense
- * else to 1
- */
-static int
-correct_dir(char *direction, int *signptr)
-{
- *signptr = 1;
- if (strncmp(RELTIME_PAST, direction, strlen(RELTIME_PAST) + 1) == 0)
- {
- *signptr = -1;
- return 1;
- }
- else
- return 0; /* invalid direction descriptor */
-}
-
-#endif
-
/*
* istinterval - returns 1, iff i_string is a valid interval descr.
* 0, iff i_string is NOT a valid interval desc.
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 824faae152b..1bd42689659 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.50 2001/09/06 03:22:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.51 2001/09/28 08:09:11 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,7 +32,7 @@
static double time2t(const int hour, const int min, const double sec);
static int EncodeSpecialTimestamp(Timestamp dt, char *str);
static Timestamp dt2local(Timestamp dt, int timezone);
-static void dt2time(Timestamp dt, int *hour, int *min, double *sec);
+
/*****************************************************************************
* USER I/O ROUTINES *
@@ -63,16 +63,12 @@ timestamp_in(PG_FUNCTION_ARGS)
switch (dtype)
{
case DTK_DATE:
- if (tm2timestamp(tm, fsec, &tz, &result) != 0)
+ if (tm2timestamp(tm, fsec, NULL, &result) != 0)
elog(ERROR, "Timestamp out of range '%s'", str);
break;
case DTK_EPOCH:
- TIMESTAMP_EPOCH(result);
- break;
-
- case DTK_CURRENT:
- TIMESTAMP_CURRENT(result);
+ result = SetEpochTimestamp();
break;
case DTK_LATE:
@@ -84,12 +80,13 @@ timestamp_in(PG_FUNCTION_ARGS)
break;
case DTK_INVALID:
- TIMESTAMP_INVALID(result);
+ elog(ERROR, "Timestamp '%s' no longer supported", str);
+ TIMESTAMP_NOEND(result);
break;
default:
- elog(ERROR, "Internal coding error, can't input timestamp '%s'", str);
- TIMESTAMP_INVALID(result); /* keep compiler quiet */
+ elog(ERROR, "Timestamp '%s' not parsed; internal coding error", str);
+ TIMESTAMP_NOEND(result);
}
PG_RETURN_TIMESTAMP(result);
@@ -103,6 +100,86 @@ timestamp_out(PG_FUNCTION_ARGS)
{
Timestamp dt = PG_GETARG_TIMESTAMP(0);
char *result;
+ struct tm tt,
+ *tm = &tt;
+ double fsec;
+ char *tzn = NULL;
+ char buf[MAXDATELEN + 1];
+
+ if (TIMESTAMP_NOT_FINITE(dt))
+ EncodeSpecialTimestamp(dt, buf);
+ else if (timestamp2tm(dt, NULL, tm, &fsec, NULL) == 0)
+ EncodeDateTime(tm, fsec, NULL, &tzn, DateStyle, buf);
+ else
+ elog(ERROR, "Unable to format timestamp; internal coding error");
+
+ result = pstrdup(buf);
+ PG_RETURN_CSTRING(result);
+}
+
+
+/* timestamptz_in()
+ * Convert a string to internal form.
+ */
+Datum
+timestamptz_in(PG_FUNCTION_ARGS)
+{
+ char *str = PG_GETARG_CSTRING(0);
+ TimestampTz result;
+ double fsec;
+ struct tm tt,
+ *tm = &tt;
+ int tz;
+ int dtype;
+ int nf;
+ char *field[MAXDATEFIELDS];
+ int ftype[MAXDATEFIELDS];
+ char lowstr[MAXDATELEN + 1];
+
+ if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
+ || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
+ elog(ERROR, "Bad timestamp external representation '%s'", str);
+
+ switch (dtype)
+ {
+ case DTK_DATE:
+ if (tm2timestamp(tm, fsec, &tz, &result) != 0)
+ elog(ERROR, "Timestamp out of range '%s'", str);
+ break;
+
+ case DTK_EPOCH:
+ result = SetEpochTimestamp();
+ break;
+
+ case DTK_LATE:
+ TIMESTAMP_NOEND(result);
+ break;
+
+ case DTK_EARLY:
+ TIMESTAMP_NOBEGIN(result);
+ break;
+
+ case DTK_INVALID:
+ elog(ERROR, "Timestamp with time zone '%s' no longer supported", str);
+ TIMESTAMP_NOEND(result);
+ break;
+
+ default:
+ elog(ERROR, "Timestamp with time zone '%s' not parsed; internal coding error", str);
+ TIMESTAMP_NOEND(result);
+ }
+
+ PG_RETURN_TIMESTAMPTZ(result);
+}
+
+/* timestamptz_out()
+ * Convert a timestamp to external form.
+ */
+Datum
+timestamptz_out(PG_FUNCTION_ARGS)
+{
+ TimestampTz dt = PG_GETARG_TIMESTAMP(0);
+ char *result;
int tz;
struct tm tt,
*tm = &tt;
@@ -110,12 +187,12 @@ timestamp_out(PG_FUNCTION_ARGS)
char *tzn;
char buf[MAXDATELEN + 1];
- if (TIMESTAMP_IS_RESERVED(dt))
+ if (TIMESTAMP_NOT_FINITE(dt))
EncodeSpecialTimestamp(dt, buf);
else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0)
EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
else
- EncodeSpecialTimestamp(DT_INVALID, buf);
+ elog(ERROR, "Unable to format timestamp with time zone; internal coding error");
result = pstrdup(buf);
PG_RETURN_CSTRING(result);
@@ -132,7 +209,7 @@ Datum
interval_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
- Interval *span;
+ Interval *result;
double fsec;
struct tm tt,
*tm = &tt;
@@ -154,25 +231,24 @@ interval_in(PG_FUNCTION_ARGS)
|| (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
elog(ERROR, "Bad interval external representation '%s'", str);
- span = (Interval *) palloc(sizeof(Interval));
+ result = (Interval *) palloc(sizeof(Interval));
switch (dtype)
{
case DTK_DELTA:
- if (tm2interval(tm, fsec, span) != 0)
- {
-#if NOT_USED
- INTERVAL_INVALID(span);
-#endif
+ if (tm2interval(tm, fsec, result) != 0)
elog(ERROR, "Bad interval external representation '%s'", str);
- }
+ break;
+
+ case DTK_INVALID:
+ elog(ERROR, "Interval '%s' no longer supported", str);
break;
default:
- elog(ERROR, "Internal coding error, can't input interval '%s'", str);
+ elog(ERROR, "Interval '%s' not parsed; internal coding error", str);
}
- PG_RETURN_INTERVAL_P(span);
+ PG_RETURN_INTERVAL_P(result);
}
/* interval_out()
@@ -189,10 +265,10 @@ interval_out(PG_FUNCTION_ARGS)
char buf[MAXDATELEN + 1];
if (interval2tm(*span, tm, &fsec) != 0)
- PG_RETURN_NULL();
+ elog(ERROR, "Unable to encode interval; internal coding error");
if (EncodeTimeSpan(tm, fsec, DateStyle, buf) != 0)
- elog(ERROR, "Unable to format interval");
+ elog(ERROR, "Unable to format interval; internal coding error");
result = pstrdup(buf);
PG_RETURN_CSTRING(result);
@@ -205,40 +281,31 @@ interval_out(PG_FUNCTION_ARGS)
static int
EncodeSpecialTimestamp(Timestamp dt, char *str)
{
- if (TIMESTAMP_IS_RESERVED(dt))
- {
- if (TIMESTAMP_IS_INVALID(dt))
- strcpy(str, INVALID);
- else if (TIMESTAMP_IS_NOBEGIN(dt))
- strcpy(str, EARLY);
- else if (TIMESTAMP_IS_NOEND(dt))
- strcpy(str, LATE);
- else if (TIMESTAMP_IS_CURRENT(dt))
- strcpy(str, DCURRENT);
- else if (TIMESTAMP_IS_EPOCH(dt))
- strcpy(str, EPOCH);
- else
- strcpy(str, INVALID);
- return TRUE;
- }
+ if (TIMESTAMP_IS_NOBEGIN(dt))
+ strcpy(str, EARLY);
+ else if (TIMESTAMP_IS_NOEND(dt))
+ strcpy(str, LATE);
+ else
+ return FALSE;
- return FALSE;
+ return TRUE;
} /* EncodeSpecialTimestamp() */
Datum
now(PG_FUNCTION_ARGS)
{
- Timestamp result;
+ TimestampTz result;
AbsoluteTime sec;
+ int usec;
- sec = GetCurrentTransactionStartTime();
+ sec = GetCurrentTransactionStartTimeUsec(&usec);
- result = (sec - ((date2j(2000, 1, 1) - date2j(1970, 1, 1)) * 86400));
+ result = (sec + (usec * 1.0e-6) - ((date2j(2000, 1, 1) - date2j(1970, 1, 1)) * 86400));
- PG_RETURN_TIMESTAMP(result);
+ PG_RETURN_TIMESTAMPTZ(result);
}
-static void
+void
dt2time(Timestamp jd, int *hour, int *min, double *sec)
{
double time;
@@ -485,9 +552,7 @@ timestamp_finite(PG_FUNCTION_ARGS)
Datum
interval_finite(PG_FUNCTION_ARGS)
{
- Interval *interval = PG_GETARG_INTERVAL_P(0);
-
- PG_RETURN_BOOL(!INTERVAL_NOT_FINITE(*interval));
+ PG_RETURN_BOOL(true);
}
@@ -495,7 +560,7 @@ interval_finite(PG_FUNCTION_ARGS)
* Relational operators for timestamp.
*---------------------------------------------------------*/
-static void
+void
GetEpochTime(struct tm * tm)
{
struct tm *t0;
@@ -518,24 +583,17 @@ GetEpochTime(struct tm * tm)
} /* GetEpochTime() */
Timestamp
-SetTimestamp(Timestamp dt)
+SetEpochTimestamp(void)
{
- struct tm tt;
+ Timestamp dt;
+ struct tm tt,
+ *tm = &tt;
- if (TIMESTAMP_IS_CURRENT(dt))
- {
- GetCurrentTime(&tt);
- tm2timestamp(&tt, 0, NULL, &dt);
- dt = dt2local(dt, -CTimeZone);
- }
- else
- { /* if (TIMESTAMP_IS_EPOCH(dt1)) */
- GetEpochTime(&tt);
- tm2timestamp(&tt, 0, NULL, &dt);
- }
+ GetEpochTime(tm);
+ tm2timestamp(tm, 0, NULL, &dt);
return dt;
-} /* SetTimestamp() */
+} /* SetEpochTimestamp() */
/*
* timestamp_relop - is timestamp1 relop timestamp2
@@ -545,19 +603,7 @@ SetTimestamp(Timestamp dt)
static int
timestamp_cmp_internal(Timestamp dt1, Timestamp dt2)
{
- if (TIMESTAMP_IS_INVALID(dt1))
- return (TIMESTAMP_IS_INVALID(dt2) ? 0 : 1);
- else if (TIMESTAMP_IS_INVALID(dt2))
- return -1;
- else
- {
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
-
- return ((dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0));
- }
+ return ((dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0));
}
Datum
@@ -632,24 +678,17 @@ timestamp_cmp(PG_FUNCTION_ARGS)
static int
interval_cmp_internal(Interval *interval1, Interval *interval2)
{
- if (INTERVAL_IS_INVALID(*interval1))
- return (INTERVAL_IS_INVALID(*interval2) ? 0 : 1);
- else if (INTERVAL_IS_INVALID(*interval2))
- return -1;
- else
- {
- double span1,
- span2;
+ double span1,
+ span2;
- span1 = interval1->time;
- if (interval1->month != 0)
- span1 += (interval1->month * (30.0 * 86400));
- span2 = interval2->time;
- if (interval2->month != 0)
- span2 += (interval2->month * (30.0 * 86400));
+ span1 = interval1->time;
+ if (interval1->month != 0)
+ span1 += (interval1->month * (30.0 * 86400));
+ span2 = interval2->time;
+ if (interval2->month != 0)
+ span2 += (interval2->month * (30.0 * 86400));
- return ((span1 < span2) ? -1 : (span1 > span2) ? 1 : 0);
- }
+ return ((span1 < span2) ? -1 : (span1 > span2) ? 1 : 0);
}
Datum
@@ -866,6 +905,9 @@ overlaps_timestamp(PG_FUNCTION_ARGS)
* "Arithmetic" operators on date/times.
*---------------------------------------------------------*/
+/* We are currently sharing some code between timestamp and timestamptz.
+ * The comparison functions are among them. - thomas 2001-09-25
+ */
Datum
timestamp_smaller(PG_FUNCTION_ARGS)
{
@@ -873,17 +915,7 @@ timestamp_smaller(PG_FUNCTION_ARGS)
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
Timestamp result;
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
-
- if (TIMESTAMP_IS_INVALID(dt1))
- result = dt2;
- else if (TIMESTAMP_IS_INVALID(dt2))
- result = dt1;
- else
- result = ((dt2 < dt1) ? dt2 : dt1);
+ result = ((dt2 < dt1) ? dt2 : dt1);
PG_RETURN_TIMESTAMP(result);
}
@@ -895,17 +927,7 @@ timestamp_larger(PG_FUNCTION_ARGS)
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
Timestamp result;
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
-
- if (TIMESTAMP_IS_INVALID(dt1))
- result = dt2;
- else if (TIMESTAMP_IS_INVALID(dt2))
- result = dt1;
- else
- result = ((dt2 > dt1) ? dt2 : dt1);
+ result = ((dt2 > dt1) ? dt2 : dt1);
PG_RETURN_TIMESTAMP(result);
}
@@ -920,16 +942,14 @@ timestamp_mi(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
-
- if (TIMESTAMP_IS_INVALID(dt1)
- || TIMESTAMP_IS_INVALID(dt2))
- TIMESTAMP_INVALID(result->time);
+ if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
+ {
+ elog(ERROR, "Unable to subtract non-finite timestamps");
+ result->time = 0;
+ }
else
result->time = JROUND(dt1 - dt2);
+
result->month = 0;
PG_RETURN_INTERVAL_P(result);
@@ -951,25 +971,111 @@ timestamp_pl_span(PG_FUNCTION_ARGS)
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
Timestamp result;
- Timestamp dt;
+
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ {
+ result = timestamp;
+ }
+ else
+ {
+ if (span->month != 0)
+ {
+ struct tm tt,
+ *tm = &tt;
+ double fsec;
+
+ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
+ {
+ tm->tm_mon += span->month;
+ if (tm->tm_mon > 12)
+ {
+ tm->tm_year += ((tm->tm_mon - 1) / 12);
+ tm->tm_mon = (((tm->tm_mon - 1) % 12) + 1);
+ }
+ else if (tm->tm_mon < 1)
+ {
+ tm->tm_year += ((tm->tm_mon / 12) - 1);
+ tm->tm_mon = ((tm->tm_mon % 12) + 12);
+ }
+
+ /* adjust for end of month boundary problems... */
+ if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
+ tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
+
+ if (tm2timestamp(tm, fsec, NULL, &timestamp) != 0)
+ {
+ elog(ERROR, "Unable to add timestamp and interval"
+ "\n\ttimestamp_pl_span() internal error encoding timestamp");
+ PG_RETURN_NULL();
+ }
+ }
+ else
+ {
+ elog(ERROR, "Unable to add timestamp and interval"
+ "\n\ttimestamp_pl_span() internal error decoding timestamp");
+ PG_RETURN_NULL();
+ }
+ }
+
+#ifdef ROUND_ALL
+ timestamp = JROUND(timestamp + span->time);
+#else
+ timestamp += span->time;
+#endif
+
+ result = timestamp;
+ }
+
+ PG_RETURN_TIMESTAMP(result);
+}
+
+Datum
+timestamp_mi_span(PG_FUNCTION_ARGS)
+{
+ Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
+ Interval *span = PG_GETARG_INTERVAL_P(1);
+ Interval tspan;
+
+ tspan.month = -span->month;
+ tspan.time = -span->time;
+
+ return DirectFunctionCall2(timestamp_pl_span,
+ TimestampGetDatum(timestamp),
+ PointerGetDatum(&tspan));
+}
+
+
+/* timestamp_pl_span()
+ * Add a interval to a timestamp with time zone data type.
+ * Note that interval has provisions for qualitative year/month
+ * units, so try to do the right thing with them.
+ * To add a month, increment the month, and use the same day of month.
+ * Then, if the next month has fewer days, set the day of month
+ * to the last day of month.
+ * Lastly, add in the "quantitative time".
+ */
+Datum
+timestamptz_pl_span(PG_FUNCTION_ARGS)
+{
+ TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
+ Interval *span = PG_GETARG_INTERVAL_P(1);
+ TimestampTz result;
int tz;
char *tzn;
if (TIMESTAMP_NOT_FINITE(timestamp))
+ {
result = timestamp;
- else if (INTERVAL_IS_INVALID(*span))
- TIMESTAMP_INVALID(result);
+ }
else
{
- dt = (TIMESTAMP_IS_RELATIVE(timestamp) ? SetTimestamp(timestamp) : timestamp);
-
if (span->month != 0)
{
struct tm tt,
*tm = &tt;
double fsec;
- if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0)
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) == 0)
{
tm->tm_mon += span->month;
if (tm->tm_mon > 12)
@@ -989,30 +1095,33 @@ timestamp_pl_span(PG_FUNCTION_ARGS)
tz = DetermineLocalTimeZone(tm);
- if (tm2timestamp(tm, fsec, &tz, &dt) != 0)
- elog(ERROR, "Unable to add timestamp and interval");
-
+ if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
+ elog(ERROR, "Unable to add timestamp and interval"
+ "\n\ttimestamptz_pl_span() internal error encoding timestamp");
}
else
- TIMESTAMP_INVALID(dt);
+ {
+ elog(ERROR, "Unable to add timestamp and interval"
+ "\n\ttimestamptz_pl_span() internal error decoding timestamp");
+ }
}
#ifdef ROUND_ALL
- dt = JROUND(dt + span->time);
+ timestamp = JROUND(timestamp + span->time);
#else
- dt += span->time;
+ timestamp += span->time;
#endif
- result = dt;
+ result = timestamp;
}
PG_RETURN_TIMESTAMP(result);
}
Datum
-timestamp_mi_span(PG_FUNCTION_ARGS)
+timestamptz_mi_span(PG_FUNCTION_ARGS)
{
- Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
+ TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
Interval tspan;
@@ -1051,36 +1160,23 @@ interval_smaller(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
- if (INTERVAL_IS_INVALID(*interval1))
+ span1 = interval1->time;
+ if (interval1->month != 0)
+ span1 += (interval1->month * (30.0 * 86400));
+ span2 = interval2->time;
+ if (interval2->month != 0)
+ span2 += (interval2->month * (30.0 * 86400));
+
+ if (span2 < span1)
{
result->time = interval2->time;
result->month = interval2->month;
}
- else if (INTERVAL_IS_INVALID(*interval2))
+ else
{
result->time = interval1->time;
result->month = interval1->month;
}
- else
- {
- span1 = interval1->time;
- if (interval1->month != 0)
- span1 += (interval1->month * (30.0 * 86400));
- span2 = interval2->time;
- if (interval2->month != 0)
- span2 += (interval2->month * (30.0 * 86400));
-
- if (span2 < span1)
- {
- result->time = interval2->time;
- result->month = interval2->month;
- }
- else
- {
- result->time = interval1->time;
- result->month = interval1->month;
- }
- }
PG_RETURN_INTERVAL_P(result);
}
@@ -1096,36 +1192,23 @@ interval_larger(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
- if (INTERVAL_IS_INVALID(*interval1))
+ span1 = interval1->time;
+ if (interval1->month != 0)
+ span1 += (interval1->month * (30.0 * 86400));
+ span2 = interval2->time;
+ if (interval2->month != 0)
+ span2 += (interval2->month * (30.0 * 86400));
+
+ if (span2 > span1)
{
result->time = interval2->time;
result->month = interval2->month;
}
- else if (INTERVAL_IS_INVALID(*interval2))
+ else
{
result->time = interval1->time;
result->month = interval1->month;
}
- else
- {
- span1 = interval1->time;
- if (interval1->month != 0)
- span1 += (interval1->month * (30.0 * 86400));
- span2 = interval2->time;
- if (interval2->month != 0)
- span2 += (interval2->month * (30.0 * 86400));
-
- if (span2 > span1)
- {
- result->time = interval2->time;
- result->month = interval2->month;
- }
- else
- {
- result->time = interval1->time;
- result->month = interval1->month;
- }
- }
PG_RETURN_INTERVAL_P(result);
}
@@ -1200,7 +1283,7 @@ interval_div(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
if (factor == 0.0)
- elog(ERROR, "interval_div: divide by 0.0 error");
+ elog(ERROR, "interval_div: divide by 0.0 error");
months = (span1->month / factor);
result->month = rint(months);
@@ -1321,16 +1404,117 @@ timestamp_age(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
+ if ((timestamp2tm(dt1, NULL, tm1, &fsec1, NULL) == 0)
+ && (timestamp2tm(dt2, NULL, tm2, &fsec2, NULL) == 0))
+ {
+ fsec = (fsec1 - fsec2);
+ tm->tm_sec = (tm1->tm_sec - tm2->tm_sec);
+ tm->tm_min = (tm1->tm_min - tm2->tm_min);
+ tm->tm_hour = (tm1->tm_hour - tm2->tm_hour);
+ tm->tm_mday = (tm1->tm_mday - tm2->tm_mday);
+ tm->tm_mon = (tm1->tm_mon - tm2->tm_mon);
+ tm->tm_year = (tm1->tm_year - tm2->tm_year);
+
+ /* flip sign if necessary... */
+ if (dt1 < dt2)
+ {
+ fsec = -fsec;
+ tm->tm_sec = -tm->tm_sec;
+ tm->tm_min = -tm->tm_min;
+ tm->tm_hour = -tm->tm_hour;
+ tm->tm_mday = -tm->tm_mday;
+ tm->tm_mon = -tm->tm_mon;
+ tm->tm_year = -tm->tm_year;
+ }
+
+ if (tm->tm_sec < 0)
+ {
+ tm->tm_sec += 60;
+ tm->tm_min--;
+ }
+
+ if (tm->tm_min < 0)
+ {
+ tm->tm_min += 60;
+ tm->tm_hour--;
+ }
+
+ if (tm->tm_hour < 0)
+ {
+ tm->tm_hour += 24;
+ tm->tm_mday--;
+ }
+
+ if (tm->tm_mday < 0)
+ {
+ if (dt1 < dt2)
+ {
+ tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
+ tm->tm_mon--;
+ }
+ else
+ {
+ tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
+ tm->tm_mon--;
+ }
+ }
+
+ if (tm->tm_mon < 0)
+ {
+ tm->tm_mon += 12;
+ tm->tm_year--;
+ }
- if (TIMESTAMP_IS_INVALID(dt1)
- || TIMESTAMP_IS_INVALID(dt2))
- TIMESTAMP_INVALID(result->time);
- else if ((timestamp2tm(dt1, NULL, tm1, &fsec1, NULL) == 0)
- && (timestamp2tm(dt2, NULL, tm2, &fsec2, NULL) == 0))
+ /* recover sign if necessary... */
+ if (dt1 < dt2)
+ {
+ fsec = -fsec;
+ tm->tm_sec = -tm->tm_sec;
+ tm->tm_min = -tm->tm_min;
+ tm->tm_hour = -tm->tm_hour;
+ tm->tm_mday = -tm->tm_mday;
+ tm->tm_mon = -tm->tm_mon;
+ tm->tm_year = -tm->tm_year;
+ }
+
+ if (tm2interval(tm, fsec, result) != 0)
+ elog(ERROR, "Unable to encode interval"
+ "\n\ttimestamp_age() internal coding error");
+ }
+ else
+ elog(ERROR, "Unable to decode timestamp"
+ "\n\ttimestamp_age() internal coding error");
+
+ PG_RETURN_INTERVAL_P(result);
+}
+
+
+/* timestamptz_age()
+ * Calculate time difference while retaining year/month fields.
+ * Note that this does not result in an accurate absolute time span
+ * since year and month are out of context once the arithmetic
+ * is done.
+ */
+Datum
+timestamptz_age(PG_FUNCTION_ARGS)
+{
+ TimestampTz dt1 = PG_GETARG_TIMESTAMP(0);
+ TimestampTz dt2 = PG_GETARG_TIMESTAMP(1);
+ Interval *result;
+ double fsec,
+ fsec1,
+ fsec2;
+ struct tm tt,
+ *tm = &tt;
+ struct tm tt1,
+ *tm1 = &tt1;
+ struct tm tt2,
+ *tm2 = &tt2;
+
+ result = (Interval *) palloc(sizeof(Interval));
+
+ if ((timestamp2tm(dt1, NULL, tm1, &fsec1, NULL) == 0)
+ && (timestamp2tm(dt2, NULL, tm2, &fsec2, NULL) == 0))
{
fsec = (fsec1 - fsec2);
tm->tm_sec = (tm1->tm_sec - tm2->tm_sec);
@@ -1472,6 +1656,60 @@ text_timestamp(PG_FUNCTION_ARGS)
}
+/* timestamptz_text()
+ * Convert timestamp with time zone to text data type.
+ */
+Datum
+timestamptz_text(PG_FUNCTION_ARGS)
+{
+ /* Input is a Timestamp, but may as well leave it in Datum form */
+ Datum timestamp = PG_GETARG_DATUM(0);
+ text *result;
+ char *str;
+ int len;
+
+ str = DatumGetCString(DirectFunctionCall1(timestamptz_out, timestamp));
+
+ len = (strlen(str) + VARHDRSZ);
+
+ result = palloc(len);
+
+ VARATT_SIZEP(result) = len;
+ memmove(VARDATA(result), str, (len - VARHDRSZ));
+
+ pfree(str);
+
+ PG_RETURN_TEXT_P(result);
+}
+
+/* text_timestamptz()
+ * Convert text string to timestamp with time zone.
+ * Text type is not null terminated, so use temporary string
+ * then call the standard input routine.
+ */
+Datum
+text_timestamptz(PG_FUNCTION_ARGS)
+{
+ text *str = PG_GETARG_TEXT_P(0);
+ int i;
+ char *sp,
+ *dp,
+ dstr[MAXDATELEN + 1];
+
+ if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
+ elog(ERROR, "Bad timestamp with time zone external representation (too long)");
+
+ sp = VARDATA(str);
+ dp = dstr;
+ for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
+ *dp++ = *sp++;
+ *dp = '\0';
+
+ return DirectFunctionCall1(timestamptz_in,
+ CStringGetDatum(dstr));
+}
+
+
/* interval_text()
* Convert interval to text data type.
*/
@@ -1484,7 +1722,7 @@ interval_text(PG_FUNCTION_ARGS)
int len;
str = DatumGetCString(DirectFunctionCall1(interval_out,
- IntervalPGetDatum(interval)));
+ IntervalPGetDatum(interval)));
len = (strlen(str) + VARHDRSZ);
@@ -1525,7 +1763,7 @@ text_interval(PG_FUNCTION_ARGS)
}
/* timestamp_trunc()
- * Extract specified field from timestamp.
+ * Truncate timestamp to specified units.
*/
Datum
timestamp_trunc(PG_FUNCTION_ARGS)
@@ -1533,8 +1771,6 @@ timestamp_trunc(PG_FUNCTION_ARGS)
text *units = PG_GETARG_TEXT_P(0);
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
Timestamp result;
- Timestamp dt;
- int tz;
int type,
val;
int i;
@@ -1542,7 +1778,6 @@ timestamp_trunc(PG_FUNCTION_ARGS)
*lp,
lowunits[MAXDATELEN + 1];
double fsec;
- char *tzn;
struct tm tt,
*tm = &tt;
@@ -1559,70 +1794,146 @@ timestamp_trunc(PG_FUNCTION_ARGS)
type = DecodeUnits(0, lowunits, &val);
if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_NULL();
+ PG_RETURN_TIMESTAMP(timestamp);
+
+ if ((type == UNITS) && (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0))
+ {
+ switch (val)
+ {
+ case DTK_MILLENNIUM:
+ tm->tm_year = (tm->tm_year / 1000) * 1000;
+ case DTK_CENTURY:
+ tm->tm_year = (tm->tm_year / 100) * 100;
+ case DTK_DECADE:
+ tm->tm_year = (tm->tm_year / 10) * 10;
+ case DTK_YEAR:
+ tm->tm_mon = 1;
+ case DTK_QUARTER:
+ tm->tm_mon = (3 * (tm->tm_mon / 4)) + 1;
+ case DTK_MONTH:
+ tm->tm_mday = 1;
+ case DTK_DAY:
+ tm->tm_hour = 0;
+ case DTK_HOUR:
+ tm->tm_min = 0;
+ case DTK_MINUTE:
+ tm->tm_sec = 0;
+ case DTK_SECOND:
+ fsec = 0;
+ break;
+
+ case DTK_MILLISEC:
+ fsec = rint(fsec * 1000) / 1000;
+ break;
+
+ case DTK_MICROSEC:
+ fsec = rint(fsec * 1000000) / 1000000;
+ break;
+
+ default:
+ elog(ERROR, "Timestamp units '%s' not supported", lowunits);
+ result = 0;
+ }
+
+ if (tm2timestamp(tm, fsec, NULL, &result) != 0)
+ elog(ERROR, "Unable to truncate timestamp to '%s'", lowunits);
+ }
else
{
- dt = (TIMESTAMP_IS_RELATIVE(timestamp) ? SetTimestamp(timestamp) : timestamp);
+ elog(ERROR, "Timestamp units '%s' not recognized", lowunits);
+ result = 0;
+ }
- if ((type == UNITS) && (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0))
- {
- switch (val)
- {
- case DTK_MILLENNIUM:
- tm->tm_year = (tm->tm_year / 1000) * 1000;
- case DTK_CENTURY:
- tm->tm_year = (tm->tm_year / 100) * 100;
- case DTK_DECADE:
- tm->tm_year = (tm->tm_year / 10) * 10;
- case DTK_YEAR:
- tm->tm_mon = 1;
- case DTK_QUARTER:
- tm->tm_mon = (3 * (tm->tm_mon / 4)) + 1;
- case DTK_MONTH:
- tm->tm_mday = 1;
- case DTK_DAY:
- tm->tm_hour = 0;
- case DTK_HOUR:
- tm->tm_min = 0;
- case DTK_MINUTE:
- tm->tm_sec = 0;
- case DTK_SECOND:
- fsec = 0;
- break;
+ PG_RETURN_TIMESTAMP(result);
+}
- case DTK_MILLISEC:
- fsec = rint(fsec * 1000) / 1000;
- break;
+/* timestamptz_trunc()
+ * Truncate timestamp to specified units.
+ */
+Datum
+timestamptz_trunc(PG_FUNCTION_ARGS)
+{
+ text *units = PG_GETARG_TEXT_P(0);
+ TimestampTz timestamp = PG_GETARG_TIMESTAMP(1);
+ TimestampTz result;
+ int tz;
+ int type,
+ val;
+ int i;
+ char *up,
+ *lp,
+ lowunits[MAXDATELEN + 1];
+ double fsec;
+ char *tzn;
+ struct tm tt,
+ *tm = &tt;
- case DTK_MICROSEC:
- fsec = rint(fsec * 1000000) / 1000000;
- break;
+ if (VARSIZE(units) - VARHDRSZ > MAXDATELEN)
+ elog(ERROR, "Interval 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';
- default:
- elog(ERROR, "Timestamp units '%s' not supported", lowunits);
- result = 0;
- }
+ type = DecodeUnits(0, lowunits, &val);
- tz = DetermineLocalTimeZone(tm);
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ PG_RETURN_TIMESTAMPTZ(timestamp);
- if (tm2timestamp(tm, fsec, &tz, &result) != 0)
- elog(ERROR, "Unable to truncate timestamp to '%s'", lowunits);
- }
-#if NOT_USED
- else if ((type == RESERV) && (val == DTK_EPOCH))
- {
- TIMESTAMP_EPOCH(result);
- result = dt - SetTimestamp(result);
- }
-#endif
- else
+ if ((type == UNITS) && (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) == 0))
+ {
+ switch (val)
{
- elog(ERROR, "Timestamp units '%s' not recognized", lowunits);
- result = 0;
+ case DTK_MILLENNIUM:
+ tm->tm_year = (tm->tm_year / 1000) * 1000;
+ case DTK_CENTURY:
+ tm->tm_year = (tm->tm_year / 100) * 100;
+ case DTK_DECADE:
+ tm->tm_year = (tm->tm_year / 10) * 10;
+ case DTK_YEAR:
+ tm->tm_mon = 1;
+ case DTK_QUARTER:
+ tm->tm_mon = (3 * (tm->tm_mon / 4)) + 1;
+ case DTK_MONTH:
+ tm->tm_mday = 1;
+ case DTK_DAY:
+ tm->tm_hour = 0;
+ case DTK_HOUR:
+ tm->tm_min = 0;
+ case DTK_MINUTE:
+ tm->tm_sec = 0;
+ case DTK_SECOND:
+ fsec = 0;
+ break;
+
+ case DTK_MILLISEC:
+ fsec = rint(fsec * 1000) / 1000;
+ break;
+
+ case DTK_MICROSEC:
+ fsec = rint(fsec * 1000000) / 1000000;
+ break;
+
+ default:
+ elog(ERROR, "Timestamp units '%s' not supported", lowunits);
+ result = 0;
}
+
+ tz = DetermineLocalTimeZone(tm);
+
+ if (tm2timestamp(tm, fsec, &tz, &result) != 0)
+ elog(ERROR, "Unable to truncate timestamp to '%s'", lowunits);
+ }
+ else
+ {
+ elog(ERROR, "Timestamp units '%s' not recognized", lowunits);
+ PG_RETURN_NULL();
}
- PG_RETURN_TIMESTAMP(result);
+ PG_RETURN_TIMESTAMPTZ(result);
}
/* interval_trunc()
@@ -1658,14 +1969,7 @@ interval_trunc(PG_FUNCTION_ARGS)
type = DecodeUnits(0, lowunits, &val);
- if (INTERVAL_IS_INVALID(*interval))
- {
-#if NOT_USED
- elog(ERROR, "Interval is not finite");
-#endif
- PG_RETURN_NULL();
- }
- else if (type == UNITS)
+ if (type == UNITS)
{
if (interval2tm(*interval, tm, &fsec) == 0)
{
@@ -1703,7 +2007,6 @@ interval_trunc(PG_FUNCTION_ARGS)
default:
elog(ERROR, "Interval units '%s' not supported", lowunits);
- PG_RETURN_NULL();
}
if (tm2interval(tm, fsec, result) != 0)
@@ -1712,28 +2015,16 @@ interval_trunc(PG_FUNCTION_ARGS)
}
else
{
- elog(NOTICE, "Interval out of range");
- PG_RETURN_NULL();
+ elog(NOTICE, "Unable to decode interval; internal coding error");
+ *result = *interval;
}
-
}
-#if NOT_USED
- else if ((type == RESERV) && (val == DTK_EPOCH))
- {
- *result = interval->time;
- if (interval->month != 0)
- {
- *result += ((365.25 * 86400) * (interval->month / 12));
- *result += ((30 * 86400) * (interval->month % 12));
- }
- }
-#endif
else
{
elog(ERROR, "Interval units '%s' not recognized",
DatumGetCString(DirectFunctionCall1(textout,
- PointerGetDatum(units))));
- PG_RETURN_NULL();
+ PointerGetDatum(units))));
+ *result = *interval;
}
PG_RETURN_INTERVAL_P(result);
@@ -1828,7 +2119,6 @@ timestamp_part(PG_FUNCTION_ARGS)
text *units = PG_GETARG_TEXT_P(0);
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
float8 result;
- Timestamp dt;
int tz;
int type,
val;
@@ -1845,7 +2135,7 @@ timestamp_part(PG_FUNCTION_ARGS)
if (VARSIZE(units) - VARHDRSZ > MAXDATELEN)
elog(ERROR, "Interval units '%s' not recognized",
DatumGetCString(DirectFunctionCall1(textout,
- PointerGetDatum(units))));
+ PointerGetDatum(units))));
up = VARDATA(units);
lp = lowunits;
for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
@@ -1857,123 +2147,276 @@ timestamp_part(PG_FUNCTION_ARGS)
type = DecodeSpecial(0, lowunits, &val);
if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_NULL();
- else
{
- dt = (TIMESTAMP_IS_RELATIVE(timestamp) ? SetTimestamp(timestamp) : timestamp);
+ result = 0;
+ PG_RETURN_FLOAT8(result);
+ }
- if ((type == UNITS) && (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0))
+ if ((type == UNITS) && (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) == 0))
+ {
+ switch (val)
{
- switch (val)
- {
- case DTK_TZ:
- result = tz;
- break;
-
- case DTK_TZ_MINUTE:
- result = tz / 60;
- TMODULO(result, dummy, 60e0);
- break;
-
- case DTK_TZ_HOUR:
- dummy = tz;
- TMODULO(dummy, result, 3600e0);
- break;
-
- case DTK_MICROSEC:
- result = (fsec * 1000000);
- break;
-
- case DTK_MILLISEC:
- result = (fsec * 1000);
- break;
+ case DTK_TZ:
+ result = tz;
+ break;
+
+ case DTK_TZ_MINUTE:
+ result = tz / 60;
+ TMODULO(result, dummy, 60e0);
+ break;
+
+ case DTK_TZ_HOUR:
+ dummy = tz;
+ TMODULO(dummy, result, 3600e0);
+ break;
+
+ case DTK_MICROSEC:
+ result = (fsec * 1000000);
+ break;
+
+ case DTK_MILLISEC:
+ result = (fsec * 1000);
+ break;
+
+ case DTK_SECOND:
+ result = (tm->tm_sec + fsec);
+ break;
+
+ case DTK_MINUTE:
+ result = tm->tm_min;
+ break;
+
+ case DTK_HOUR:
+ result = tm->tm_hour;
+ break;
+
+ case DTK_DAY:
+ result = tm->tm_mday;
+ break;
+
+ case DTK_MONTH:
+ result = tm->tm_mon;
+ break;
+
+ case DTK_QUARTER:
+ result = ((tm->tm_mon - 1) / 3) + 1;
+ break;
+
+ case DTK_WEEK:
+ result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
+ break;
+
+ case DTK_YEAR:
+ result = tm->tm_year;
+ break;
+
+ case DTK_DECADE:
+ result = (tm->tm_year / 10);
+ break;
+
+ case DTK_CENTURY:
+ result = (tm->tm_year / 100);
+ break;
+
+ case DTK_MILLENNIUM:
+ result = (tm->tm_year / 1000);
+ break;
+
+ default:
+ elog(ERROR, "Timestamp units '%s' not supported", lowunits);
+ result = 0;
+ }
- case DTK_SECOND:
- result = (tm->tm_sec + fsec);
- break;
+ }
+ else if (type == RESERV)
+ {
+ switch (val)
+ {
+ case DTK_EPOCH:
+ result = timestamp - SetEpochTimestamp();
+ break;
- case DTK_MINUTE:
- result = tm->tm_min;
- break;
+ case DTK_DOW:
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
+ elog(ERROR, "Unable to encode timestamp");
- case DTK_HOUR:
- result = tm->tm_hour;
- break;
+ result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
+ break;
- case DTK_DAY:
- result = tm->tm_mday;
- break;
+ case DTK_DOY:
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
+ elog(ERROR, "Unable to encode timestamp");
- case DTK_MONTH:
- result = tm->tm_mon;
- break;
+ result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
+ - date2j(tm->tm_year, 1, 1) + 1);
+ break;
- case DTK_QUARTER:
- result = ((tm->tm_mon - 1) / 3) + 1;
- break;
+ default:
+ elog(ERROR, "Timestamp units '%s' not supported", lowunits);
+ result = 0;
+ }
- case DTK_WEEK:
- result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
- break;
+ }
+ else
+ {
+ elog(ERROR, "Timestamp units '%s' not recognized", lowunits);
+ result = 0;
+ }
- case DTK_YEAR:
- result = tm->tm_year;
- break;
+ PG_RETURN_FLOAT8(result);
+}
- case DTK_DECADE:
- result = (tm->tm_year / 10);
- break;
+/* timestamptz_part()
+ * Extract specified field from timestamp with time zone.
+ */
+Datum
+timestamptz_part(PG_FUNCTION_ARGS)
+{
+ text *units = PG_GETARG_TEXT_P(0);
+ TimestampTz timestamp = PG_GETARG_TIMESTAMP(1);
+ float8 result;
+ int tz;
+ int type,
+ val;
+ int i;
+ char *up,
+ *lp,
+ lowunits[MAXDATELEN + 1];
+ double dummy;
+ double fsec;
+ char *tzn;
+ struct tm tt,
+ *tm = &tt;
- case DTK_CENTURY:
- result = (tm->tm_year / 100);
- break;
+ if (VARSIZE(units) - VARHDRSZ > MAXDATELEN)
+ elog(ERROR, "Interval 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';
- case DTK_MILLENNIUM:
- result = (tm->tm_year / 1000);
- break;
+ type = DecodeUnits(0, lowunits, &val);
+ if (type == IGNORE)
+ type = DecodeSpecial(0, lowunits, &val);
- default:
- elog(ERROR, "Timestamp units '%s' not supported", lowunits);
- result = 0;
- }
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ {
+ result = 0;
+ PG_RETURN_FLOAT8(result);
+ }
- }
- else if (type == RESERV)
+ if ((type == UNITS) && (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) == 0))
+ {
+ switch (val)
{
- switch (val)
- {
- case DTK_EPOCH:
- TIMESTAMP_EPOCH(result);
- result = dt - SetTimestamp(result);
- break;
+ case DTK_TZ:
+ result = tz;
+ break;
+
+ case DTK_TZ_MINUTE:
+ result = tz / 60;
+ TMODULO(result, dummy, 60e0);
+ break;
+
+ case DTK_TZ_HOUR:
+ dummy = tz;
+ TMODULO(dummy, result, 3600e0);
+ break;
+
+ case DTK_MICROSEC:
+ result = (fsec * 1000000);
+ break;
+
+ case DTK_MILLISEC:
+ result = (fsec * 1000);
+ break;
+
+ case DTK_SECOND:
+ result = (tm->tm_sec + fsec);
+ break;
+
+ case DTK_MINUTE:
+ result = tm->tm_min;
+ break;
+
+ case DTK_HOUR:
+ result = tm->tm_hour;
+ break;
+
+ case DTK_DAY:
+ result = tm->tm_mday;
+ break;
+
+ case DTK_MONTH:
+ result = tm->tm_mon;
+ break;
+
+ case DTK_QUARTER:
+ result = ((tm->tm_mon - 1) / 3) + 1;
+ break;
+
+ case DTK_WEEK:
+ result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
+ break;
+
+ case DTK_YEAR:
+ result = tm->tm_year;
+ break;
+
+ case DTK_DECADE:
+ result = (tm->tm_year / 10);
+ break;
+
+ case DTK_CENTURY:
+ result = (tm->tm_year / 100);
+ break;
+
+ case DTK_MILLENNIUM:
+ result = (tm->tm_year / 1000);
+ break;
+
+ default:
+ elog(ERROR, "Timestamp with time zone units '%s' not supported", lowunits);
+ result = 0;
+ }
- case DTK_DOW:
- if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) != 0)
- elog(ERROR, "Unable to encode timestamp");
+ }
+ else if (type == RESERV)
+ {
+ switch (val)
+ {
+ case DTK_EPOCH:
+ result = timestamp - SetEpochTimestamp();
+ break;
- result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
- break;
+ case DTK_DOW:
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
+ elog(ERROR, "Unable to encode timestamp with time zone");
- case DTK_DOY:
- if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) != 0)
- elog(ERROR, "Unable to encode timestamp");
+ result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
+ break;
- result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
- - date2j(tm->tm_year, 1, 1) + 1);
- break;
+ case DTK_DOY:
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
+ elog(ERROR, "Unable to encode timestamp with time zone");
- default:
- elog(ERROR, "Timestamp units '%s' not supported", lowunits);
- result = 0;
- }
+ result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
+ - date2j(tm->tm_year, 1, 1) + 1);
+ break;
- }
- else
- {
- elog(ERROR, "Timestamp units '%s' not recognized", lowunits);
- result = 0;
+ default:
+ elog(ERROR, "Timestamp with time zone units '%s' not supported", lowunits);
+ result = 0;
}
}
+ else
+ {
+ elog(ERROR, "Timestamp with time zone units '%s' not recognized", lowunits);
+ result = 0;
+ }
PG_RETURN_FLOAT8(result);
}
@@ -2012,14 +2455,7 @@ interval_part(PG_FUNCTION_ARGS)
if (type == IGNORE)
type = DecodeSpecial(0, lowunits, &val);
- if (INTERVAL_IS_INVALID(*interval))
- {
-#if NOT_USED
- elog(ERROR, "Interval is not finite");
-#endif
- result = 0;
- }
- else if (type == UNITS)
+ if (type == UNITS)
{
if (interval2tm(*interval, tm, &fsec) == 0)
{
@@ -2074,7 +2510,7 @@ interval_part(PG_FUNCTION_ARGS)
break;
default:
- elog(ERROR, "Interval units '%s' not yet supported",
+ elog(ERROR, "Interval units '%s' not supported",
DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(units))));
result = 0;
@@ -2083,7 +2519,8 @@ interval_part(PG_FUNCTION_ARGS)
}
else
{
- elog(NOTICE, "Interval out of range");
+ elog(NOTICE, "Unable to decode interval"
+ "\n\tinterval_part() internal coding error");
result = 0;
}
}
@@ -2116,8 +2553,142 @@ timestamp_zone(PG_FUNCTION_ARGS)
{
text *zone = PG_GETARG_TEXT_P(0);
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
+ TimestampTz result;
+ int tz;
+ int type,
+ val;
+ int i;
+ char *up,
+ *lp,
+ lowzone[MAXDATELEN + 1];
+
+ if (VARSIZE(zone) - VARHDRSZ > MAXDATELEN)
+ elog(ERROR, "Time zone '%s' not recognized",
+ DatumGetCString(DirectFunctionCall1(textout,
+ PointerGetDatum(zone))));
+
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ PG_RETURN_TIMESTAMPTZ(timestamp);
+
+ up = VARDATA(zone);
+ lp = lowzone;
+ for (i = 0; i < (VARSIZE(zone) - VARHDRSZ); i++)
+ *lp++ = tolower((unsigned char) *up++);
+ *lp = '\0';
+
+ type = DecodeSpecial(0, lowzone, &val);
+
+ if ((type == TZ) || (type == DTZ))
+ {
+ tz = val * 60;
+ result = timestamp - tz;
+ }
+ else
+ {
+ elog(ERROR, "Time zone '%s' not recognized", lowzone);
+ PG_RETURN_NULL();
+ }
+
+ PG_RETURN_TIMESTAMPTZ(result);
+} /* timestamp_zone() */
+
+/* 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)
+{
+ Interval *zone = PG_GETARG_INTERVAL_P(0);
+ Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
+ TimestampTz result;
+ int tz;
+
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ PG_RETURN_TIMESTAMPTZ(timestamp);
+
+ if (zone->month != 0)
+ elog(ERROR, "INTERVAL time zone '%s' not legal (month specified)",
+ DatumGetCString(DirectFunctionCall1(interval_out,
+ PointerGetDatum(zone))));
+
+ tz = -(zone->time);
+ result = timestamp - tz;
+
+ PG_RETURN_TIMESTAMPTZ(result);
+} /* timestamp_izone() */
+
+/* timestamp_timestamptz()
+ * Convert local timestamp to timestamp at GMT
+ */
+Datum
+timestamp_timestamptz(PG_FUNCTION_ARGS)
+{
+ Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
+ TimestampTz result;
+ struct tm tt,
+ *tm = &tt;
+ double fsec;
+ int tz;
+
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ {
+ result = timestamp;
+ }
+ else
+ {
+ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) != 0)
+ elog(ERROR, "Unable to convert timestamp to timestamp with time zone (tm)");
+
+ tz = DetermineLocalTimeZone(tm);
+
+ if (tm2timestamp(tm, fsec, &tz, &result) != 0)
+ elog(ERROR, "Unable to convert timestamp to timestamp with time zone");
+ }
+
+ PG_RETURN_TIMESTAMPTZ(result);
+}
+
+/* timestamptz_timestamp()
+ * Convert timestamp at GMT to local timestamp
+ */
+Datum
+timestamptz_timestamp(PG_FUNCTION_ARGS)
+{
+ TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
+ Timestamp result;
+ struct tm tt,
+ *tm = &tt;
+ double fsec;
+ char *tzn;
+ int tz;
+
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ {
+ result = timestamp;
+ }
+ else
+ {
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
+ elog(ERROR, "Unable to convert timestamp with time zone to timestamp (tm)");
+
+ if (tm2timestamp(tm, fsec, NULL, &result) != 0)
+ elog(ERROR, "Unable to convert timestamp with time zone to timestamp");
+ }
+
+ PG_RETURN_TIMESTAMP(result);
+}
+
+/* timestamptz_zone()
+ * Encode timestamp with time zone type with specified time zone.
+ */
+Datum
+timestamptz_zone(PG_FUNCTION_ARGS)
+{
+ text *zone = PG_GETARG_TEXT_P(0);
+ TimestampTz timestamp = PG_GETARG_TIMESTAMP(1);
text *result;
- Timestamp dt;
+ TimestampTz dt;
int tz;
int type,
val;
@@ -2146,17 +2717,18 @@ timestamp_zone(PG_FUNCTION_ARGS)
type = DecodeSpecial(0, lowzone, &val);
if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_NULL();
- else if ((type == TZ) || (type == DTZ))
+ PG_RETURN_TEXT_P(pstrdup(""));
+
+ if ((type == TZ) || (type == DTZ))
{
tm->tm_isdst = ((type == DTZ) ? 1 : 0);
tz = val * 60;
- dt = (TIMESTAMP_IS_RELATIVE(timestamp) ? SetTimestamp(timestamp) : timestamp);
- dt = dt2local(dt, tz);
+ dt = dt2local(timestamp, tz);
if (timestamp2tm(dt, NULL, tm, &fsec, NULL) != 0)
- elog(ERROR, "Timestamp not legal");
+ elog(ERROR, "Unable to decode timestamp"
+ "\n\ttimestamp_zone() internal coding error");
up = upzone;
lp = lowzone;
@@ -2177,23 +2749,23 @@ timestamp_zone(PG_FUNCTION_ARGS)
else
{
elog(ERROR, "Time zone '%s' not recognized", lowzone);
- result = NULL;
+ PG_RETURN_TEXT_P(pstrdup(""));
}
PG_RETURN_TEXT_P(result);
-} /* timestamp_zone() */
+} /* timestamptz_zone() */
-/* timestamp_izone()
- * Encode timestamp type with specified time interval as time 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.
*/
Datum
-timestamp_izone(PG_FUNCTION_ARGS)
+timestamptz_izone(PG_FUNCTION_ARGS)
{
Interval *zone = PG_GETARG_INTERVAL_P(0);
- Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
+ TimestampTz timestamp = PG_GETARG_TIMESTAMP(1);
text *result;
- Timestamp dt;
+ TimestampTz dt;
int tz;
char *tzn = "";
double fsec;
@@ -2203,19 +2775,21 @@ timestamp_izone(PG_FUNCTION_ARGS)
int len;
if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_NULL();
+ PG_RETURN_TEXT_P(pstrdup(""));
if (zone->month != 0)
- elog(ERROR, "INTERVAL time zone not legal (month specified)");
+ elog(ERROR, "INTERVAL time zone '%s' not legal (month specified)",
+ DatumGetCString(DirectFunctionCall1(interval_out,
+ PointerGetDatum(zone))));
tm->tm_isdst = -1;
tz = -(zone->time);
- dt = (TIMESTAMP_IS_RELATIVE(timestamp) ? SetTimestamp(timestamp) : timestamp);
- dt = dt2local(dt, tz);
+ dt = dt2local(timestamp, tz);
if (timestamp2tm(dt, NULL, tm, &fsec, NULL) != 0)
- elog(ERROR, "Timestamp not legal");
+ elog(ERROR, "Unable to decode timestamp"
+ "\n\ttimestamp_izone() internal coding error");
EncodeDateTime(tm, fsec, &tz, &tzn, USE_ISO_DATES, buf);
len = (strlen(buf) + VARHDRSZ);
@@ -2225,4 +2799,4 @@ timestamp_izone(PG_FUNCTION_ARGS)
memmove(VARDATA(result), buf, (len - VARHDRSZ));
PG_RETURN_TEXT_P(result);
-} /* timestamp_izone() */
+} /* timestamptz_izone() */