]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
From: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov>
authorMarc G. Fournier <scrappy@hub.org>
Wed, 2 Apr 1997 18:36:24 +0000 (18:36 +0000)
committerMarc G. Fournier <scrappy@hub.org>
Wed, 2 Apr 1997 18:36:24 +0000 (18:36 +0000)
Subject: [HACKERS] More date time functions

Here are some additional patches mostly related to the date and time
data types. It includes some type conversion routines to move between
the different date types and some other date manipulation routines such
as date_part(units,datetime).

I noticed Edmund Mergl et al's neat trick for getting function overloading
for builtin functions, so started to use that for the date and time stuff.
Later, if someone figures out how to get function overloading directly
for internal C code, then we can move to that technique.

These patches include documentation updates (don't faint!) for the built-in
man page. Doesn't yet include mention of timestamp, since I don't know
much about it and since it may change a bit to become a _real_ ANSI timestamp
which would include parser support for the declaration syntax (what do you
think, Dan?).

The patches were developed on the 970330 release, but have been rebuilt
off of the 970402 release. The first patch below is to get libpq to compile,
on my Linux box, but is not related to the rest of the patches and you can
choose not to apply that one at this time. Thanks in advance, scrappy!

12 files changed:
src/backend/utils/adt/date.c
src/backend/utils/adt/datetime.c
src/backend/utils/adt/dt.c
src/backend/utils/adt/nabstime.c
src/backend/utils/adt/timestamp.c
src/include/catalog/pg_aggregate.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/include/utils/dt.h
src/include/utils/nabstime.h
src/man/built-in.3

index 8d2587ce3858b4736809d7fabc422f4e7f4687d0..3f6d192424b28daa0acbf3fa63b4b102970b5635 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.6 1997/03/14 23:19:57 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.7 1997/04/02 18:33:09 scrappy Exp $
  *
  * NOTES
  *   This code is actually (almost) unused.
 
 #include "postgres.h"
 #include "miscadmin.h"
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
 #include "access/xact.h"
 #include "utils/builtins.h"    /* where function declarations go */
 #include "utils/palloc.h"
 #include "utils/dt.h"
 
-#ifndef USE_NEW_TIME_CODE
-#define USE_NEW_TIME_CODE 1
-#endif
-
 #define        INVALID_RELTIME_STR     "Undefined RelTime"
 #define        INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
 #define        RELTIME_LABEL           '@'
@@ -235,6 +234,55 @@ char *tintervalout(TimeInterval interval)
  *   PUBLIC ROUTINES                                                         *
  *****************************************************************************/
 
+RelativeTime
+timespan_reltime(TimeSpan *timespan)
+{
+    RelativeTime time;
+    double span;
+
+    if (!PointerIsValid(timespan))
+       time = INVALID_RELTIME;
+
+    if (TIMESPAN_IS_INVALID(*timespan)) {
+       time = INVALID_RELTIME;
+
+    } else {
+       span = ((((double) 30*86400)*timespan->month) + timespan->time);
+
+#ifdef DATEDEBUG
+printf( "timespan_reltime- convert m%d s%f to %f [%d %d]\n",
+ timespan->month, timespan->time, span, INT_MIN, INT_MAX);
+#endif
+
+       time = (((span > INT_MIN) && (span < INT_MAX))? span: INVALID_RELTIME);
+    };
+
+    return(time);
+} /* timespan_reltime() */
+
+
+TimeSpan *
+reltime_timespan(RelativeTime reltime)
+{
+    TimeSpan *result;
+
+    if (!PointerIsValid(result = PALLOCTYPE(TimeSpan)))
+        elog(WARN,"Memory allocation failed, can't convert reltime to timespan",NULL);
+
+    switch(reltime) {
+    case INVALID_RELTIME:
+       TIMESPAN_INVALID(*result);
+       break;
+
+    default:
+       result->time = reltime;
+       result->month = 0;
+    };
+
+    return(result);
+} /* reltime_timespan() */
+
+
 /*
  *     mktinterval     - creates a time interval with endpoints t1 and t2
  */
index e5569281d0bdc3b26e81ad778ff9c2140a7e3818..43207b2a87a86db55b239d16f3c70241ff3097cc 100644 (file)
@@ -7,18 +7,19 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.1 1997/03/14 23:20:01 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.2 1997/04/02 18:33:22 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include <stdio.h>             /* for sprintf() */
 #include <string.h>
 
-#include <postgres.h>
-#include <miscadmin.h>
-#include <utils/builtins.h>
-#include <utils/nabstime.h>
-#include <utils/datetime.h>
+#include "postgres.h"
+#include "miscadmin.h"
+#include "utils/builtins.h"
+#include "utils/nabstime.h"
+#include "utils/datetime.h"
+#include "access/xact.h"
 
 static int     day_tab[2][12] = {
        {31,28,31,30,31,30,31,31,30,31,30,31},
@@ -72,36 +73,23 @@ printf( "date_in- input string is %s\n", str);
        elog(WARN,"Bad date external representation %s",str);
 
     switch (dtype) {
-#if FALSE
     case DTK_DATE:
-       date = date2j(tm->tm_year,tm->tm_mon,tm->tm_mday);
-       time = time2j(tm->tm_hour,tm->tm_min,(double)tm->tm_sec);
-       if (tzp != 0) {
-            j2local(&date, &time, -(tzp*60));
-       } else {
-            j2local(&date, &time, -timezone);
-       };
        break;
-#endif
+
+    case DTK_CURRENT:
+       GetCurrentTime(tm);
+       break;
 
     case DTK_EPOCH:
        tm->tm_year = 1970;
        tm->tm_mon = 1;
        tm->tm_mday = 1;
-    case DTK_DATE:
        break;
 
     default:
        elog(WARN,"Unrecognized date external representation %s",str);
     };
 
-#if FALSE
-    if (tm->tm_year < 70)
-       tm->tm_year += 2000;
-    else if (tm->tm_year < 100)
-       tm->tm_year += 1900;
-#endif
-
     if (tm->tm_year < 0 || tm->tm_year > 32767)
        elog(WARN, "date_in: year must be limited to values 0 through 32767 in '%s'", str);
     if (tm->tm_mon < 1 || tm->tm_mon > 12)
@@ -256,6 +244,82 @@ date_mii(DateADT dateVal, int4 days)
   return(date_pli(dateVal, -days));
 } /* date_mii() */
 
+
+/* date_datetime()
+ * Convert date to datetime data type.
+ */
+DateTime *
+date_datetime(int4 dateVal)
+{
+    DateTime *result;
+
+    if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
+       elog(WARN,"Memory allocation failed, can't convert date to datetime",NULL);
+
+    *result = (dateVal - date2j( 2000, 1, 1));
+    *result *= 86400;
+
+    return(result);
+} /* date_datetime() */
+
+
+/* datetime_date()
+ * Convert datetime to date data type.
+ */
+DateADT
+datetime_date(DateTime *datetime)
+{
+    DateADT result;
+
+    if (!PointerIsValid(datetime))
+       elog(WARN,"Unable to convert null datetime to date",NULL);
+
+    result = (*datetime / 86400);
+
+    return(result);
+} /* datetime_date() */
+
+
+/* abstime_date()
+ * Convert abstime to date data type.
+ */
+DateADT
+abstime_date(AbsoluteTime abstime)
+{
+    DateADT result;
+    struct tt, *tm = &tt;
+
+    switch (abstime) {
+    case INVALID_ABSTIME:
+    case NOSTART_ABSTIME:
+    case NOEND_ABSTIME:
+       elog(WARN,"Unable to convert reserved abstime value to date",NULL);
+       break;
+
+    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:
+#if FALSE
+       tm = localtime((time_t *) &abstime);
+       tm->tm_year += 1900;
+       tm->tm_mon += 1;
+       /* XXX must shift to local time before converting - tgl 97/04/01 */
+#endif
+       abstime2tm(abstime, &CTimeZone, tm);
+       result = date2j(tm->tm_year,tm->tm_mon,tm->tm_mday) - date2j(2000,1,1);
+       break;
+    };
+
+    return(result);
+} /* abstime_date() */
+
 #else
 
 bool
@@ -392,69 +456,15 @@ date_smaller(int4 dateVal1, int4 dateVal2)
 int32
 date_mi(int4 dateVal1, int4 dateVal2)
 {
-#if USE_NEW_TIME_CODE
-
     DateADT *date1, *date2;
     int days;
+
     date1 = (DateADT *) &dateVal1;
     date2 = (DateADT *) &dateVal2;
 
     days = (date2j(date1->year, date1->month, date1->day)
           - date2j(date2->year, date2->month, date2->day));
 
-#else
-
-  DateADT dv1, dv2;
-  DateADT *date1, *date2;
-  int32 days = 0;
-  int i;
-
-  /* This circumlocution allows us to assume that date1 is always
-     before date2.  */
-  dv1 = date_smaller (dateVal1, dateVal2);
-  dv2 = date_larger (dateVal1, dateVal2);
-  date1 = (DateADT *) &dv1;
-  date2 = (DateADT *) &dv2;
-
-  /* Sum number of days in each full year between date1 and date2.  */
-  for (i = date1->year + 1; i < date2->year; ++i)
-    days += isleap(i) ? 366 : 365;
-
-  if (days)
-    {
-      /* We need to wrap around the year.  Add in number of days in each
-        full month from date1 to end of year.  */
-      for (i = date1->month + 1; i <= 12; ++i)
-       days += day_tab[isleap(date1->year)][i - 1];
-
-      /* Add in number of days in each full month from start of year to
-        date2.  */
-      for (i = 1; i < date2->month; ++i)
-       days += day_tab[isleap(date2->year)][i - 1];
-    }
-  else
-    {
-      /* Add in number of days in each full month from date1 to date2.  */
-      for (i = date1->month + 1; i < date2->month; ++i)
-       days += day_tab[isleap(date1->year)][i - 1];
-    }
-
-  if (days || date1->month != date2->month)
-    {
-      /* Add in number of days left in month for date1.  */
-      days += day_tab[isleap(date1->year)][date1->month - 1] - date1->day;
-
-      /* Add in day of month of date2.  */
-      days += date2->day;
-    }
-  else
-    {
-      /* Everything's in the same month, so just subtract the days!  */
-      days = date2->day - date1->day;
-    }
-
-#endif
-
   return (days);
 }
 
@@ -463,8 +473,6 @@ date_mi(int4 dateVal1, int4 dateVal2)
 int4
 date_pli(int4 dateVal, int32 days)
 {
-#if USE_NEW_TIME_CODE
-
     DateADT *date1 = (DateADT *) &dateVal;
     int date, year, month, day;
 
@@ -474,41 +482,6 @@ date_pli(int4 dateVal, int32 days)
     date1->month = month;
     date1->day = day;
 
-#else
-
-    DateADT *date1 = (DateADT *) &dateVal;
-    /* Use separate day variable because date1->day is a narrow type.  */
-    int32 day = date1->day + days;
-
-    if (days > 0) {
-       /* Loop as long as day has wrapped around end of month.  */
-       while (day > day_tab[isleap(date1->year)][date1->month - 1]) {
-           day -= day_tab[isleap(date1->year)][date1->month - 1];
-           if (++date1->month > 12) {
-             /* Month wrapped around. */
-             date1->month = 1;
-             ++date1->year;
-           }
-       }
-
-    } else {
-       /* Loop as long as day has wrapped around beginning of month.  */
-       while (day < 1) {
-           /* Decrement month first, because a negative day number
-              should be held as relative to the previous month's end.  */
-           if (--date1->month < 1) {
-               /* Month wrapped around. */
-               date1->month = 12;
-               --date1->year;
-           }
-
-           day += day_tab[isleap(date1->year)][date1->month - 1];
-       }
-    }
-    date1->day = day;
-
-#endif
-
     return (dateVal);
 } /* date_pli() */
 
@@ -519,8 +492,93 @@ date_mii(int4 dateVal, int32 days)
     return (date_pli(dateVal, -days));
 }
 
+DateTime *
+date_datetime(int4 dateVal)
+{
+    DateTime *result;
+    DateADT *date = (DateADT *) &dateVal;
+
+    if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
+       elog(WARN,"Memory allocation failed, can't convert date to datetime",NULL);
+
+    *result = (date2j(date->year, date->month, date->day) - date2j( 2000, 1, 1));
+    *result *= 86400;
+
+#ifdef DATEDEBUG
+printf( "date_datetime- convert %04d-%02d-%02d to %f\n",
+ date->year, date->month, date->day, *result);
+#endif
+
+    return(result);
+} /* date_datetime() */
+
+int4
+datetime_date(DateTime *datetime)
+{
+    int4 result;
+    int year, month, day;
+    DateADT *date = (DateADT *) &result;
+
+    if (!PointerIsValid(datetime))
+       elog(WARN,"Unable to convert null datetime to date",NULL);
+
+    j2date( ((*datetime / 86400) + date2j( 2000, 1, 1)), &year, &month, &day);
+    date->year = year;
+    date->month = month;
+    date->day = day;
+
+    return(result);
+} /* datetime_date() */
+
+int4
+abstime_date(AbsoluteTime abstime)
+{
+    int4 result;
+    DateADT *date = (DateADT *) &result;
+    struct tm tt, *tm = &tt;
+
+    switch (abstime) {
+    case INVALID_ABSTIME:
+    case NOSTART_ABSTIME:
+    case NOEND_ABSTIME:
+       elog(WARN,"Unable to convert reserved abstime value to date",NULL);
+       break;
+
+    case EPOCH_ABSTIME:
+       date->year = 1970;
+       date->month = 1;
+       date->day = 1;
+       break;
+
+    case CURRENT_ABSTIME:
+#if FALSE
+       GetCurrentTime(tm);
+#endif
+       abstime = GetCurrentTransactionStartTime() + CTimeZone;
+       date->year = tm->tm_year;
+       date->month = tm->tm_mon;
+       date->day = tm->tm_mday;
+       break;
+
+    default:
+#if FALSE
+       tm = localtime((time_t *) &abstime);
+       tm->tm_year += 1900;
+       tm->tm_mon += 1;
+#endif
+       abstime2tm(abstime, &CTimeZone, tm);
+       date->year = tm->tm_year;
+       date->month = tm->tm_mon;
+       date->day = tm->tm_mday;
+       break;
+    };
+
+    return(result);
+} /* abstime_date() */
+
 #endif
 
+
 /*****************************************************************************
  *   Time ADT
  *****************************************************************************/
@@ -583,15 +641,14 @@ time_out(TimeADT *time)
        return NULL;
 
     if (time->sec == 0.0) {
-       sprintf(buf, "%02d:%02d",
-               (int)time->hr, (int)time->min);
+       sprintf(buf, "%02d:%02d", (int)time->hr, (int)time->min);
     } else {
        if (((int) time->sec) == time->sec) {
            sprintf(buf, "%02d:%02d:%02d",
-                   (int)time->hr, (int)time->min, (int)time->sec);
+             (int)time->hr, (int)time->min, (int)time->sec);
        } else {
            sprintf(buf, "%02d:%02d:%09.6f",
-                   (int)time->hr, (int)time->min, time->sec);
+             (int)time->hr, (int)time->min, time->sec);
        };
     };
 
@@ -666,6 +723,29 @@ time_cmp(TimeADT *time1, TimeADT *time2)
     return((*time1 < *time2)? -1: (((*time1 < *time2)? 1: 0)));
 } /* time_cmp() */
 
+
+/* datetime_datetime()
+ * Convert date and time to datetime data type.
+ */
+DateTime *
+datetime_datetime(DateADT date, TimeADT *time)
+{
+    DateTime *result;
+
+    if (!PointerIsValid(time)) {
+       if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
+           elog(WARN,"Memory allocation failed, can't convert to datetime",NULL);
+
+       DATETIME_INVALID(*result);
+
+    } else {
+       result = date_datetime(date);
+       *result += *time;
+    };
+
+    return(result);
+} /* datetime_datetime() */
+
 #else
 
 bool
@@ -734,6 +814,34 @@ time_cmp(TimeADT *time1, TimeADT *time2)
     return 0;
 }
 
+DateTime *
+datetime_datetime(int4 dateVal, TimeADT *time)
+{
+    DateTime *result;
+#ifdef DATEDEBUG
+    DateADT *date = (DateADT *) &dateVal;
+#endif
+
+    if (!PointerIsValid(time)) {
+       if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
+           elog(WARN,"Memory allocation failed, can't convert to datetime",NULL);
+
+       DATETIME_INVALID(*result);
+
+    } else {
+
+#ifdef DATEDEBUG
+printf( "datetime_datetime- convert %04d-%02d-%02d %02d:%02d:%05.2f\n",
+ date->year, date->month, date->day, time->hr, time->min, time->sec);
+#endif
+
+       result = date_datetime(dateVal);
+       *result += (((time->hr*60)+time->min)*60+time->sec);
+    };
+
+    return(result);
+} /* datetime_datetime() */
+
 #endif
 
 int32   /* RelativeTime */
index f56eb68a5f3b1de495c2d26f67d3ebf6feafc5bd..28f31a147259fbbcac8f556b396a2548c6f66da3 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.13 1997/03/28 07:16:59 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.14 1997/04/02 18:33:32 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,7 +19,7 @@
 #include <errno.h>
 
 #include "postgres.h"
-#include <miscadmin.h>
+#include "miscadmin.h"
 #ifdef HAVE_FLOAT_H
 # include <float.h>
 #endif
 #define USE_DATE_CACHE 1
 
 
+#define isleap(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
+
+int mdays[] = {31, 28, 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};
 
@@ -55,26 +59,26 @@ datetime_in(char *str)
 
     double fsec;
     struct tm tt, *tm = &tt;
-    int tzp;
+    int tz;
     int dtype;
     int nf;
     char *field[MAXDATEFIELDS];
     int ftype[MAXDATEFIELDS];
-    char lowstr[MAXDATELEN];
+    char lowstr[MAXDATELEN+1];
 
     if (!PointerIsValid(str))
-       elog(WARN, "Bad (null) datetime external representation", NULL);
+       elog(WARN,"Bad (null) datetime external representation",NULL);
 
     if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
-      || (DecodeDateTime( field, ftype, nf, &dtype, tm, &fsec, &tzp) != 0))
+      || (DecodeDateTime( field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
        elog(WARN,"Bad datetime external representation %s",str);
 
     if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
-       elog(WARN, "Memory allocation failed, can't input datetime '%s'",str);
+       elog(WARN,"Memory allocation failed, can't input datetime '%s'",str);
 
     switch (dtype) {
     case DTK_DATE:
-       *result = tm2datetime( tm, fsec, tzp);
+       *result = tm2datetime( tm, fsec, &tz);
 
 #ifdef DATEDEBUG
 printf( "datetime_in- date is %f\n", *result);
@@ -103,7 +107,7 @@ printf( "datetime_in- date is %f\n", *result);
        break;
 
     default:
-       elog(WARN, "Internal coding error, can't input datetime '%s'",str);
+       elog(WARN,"Internal coding error, can't input datetime '%s'",str);
     };
 
     return(result);
@@ -118,7 +122,7 @@ datetime_out(DateTime *dt)
     char *result;
     struct tm tt, *tm = &tt;
     double fsec;
-    char buf[MAXDATELEN];
+    char buf[MAXDATELEN+1];
 
     if (!PointerIsValid(dt))
        return(NULL);
@@ -126,7 +130,7 @@ datetime_out(DateTime *dt)
     if (DATETIME_IS_RESERVED(*dt)) {
        EncodeSpecialDateTime(*dt, buf);
 
-    } else if (datetime2tm( *dt, tm, &fsec) == 0) {
+    } else if (datetime2tm( *dt, &CTimeZone, tm, &fsec) == 0) {
        EncodeDateTime(tm, fsec, DateStyle, buf);
 
     } else {
@@ -134,7 +138,7 @@ datetime_out(DateTime *dt)
     };
 
     if (!PointerIsValid(result = PALLOC(strlen(buf)+1)))
-       elog(WARN, "Memory allocation failed, can't output datetime", NULL);
+       elog(WARN,"Memory allocation failed, can't output datetime",NULL);
 
     strcpy( result, buf);
 
@@ -159,7 +163,7 @@ timespan_in(char *str)
     int nf;
     char *field[MAXDATEFIELDS];
     int ftype[MAXDATEFIELDS];
-    char lowstr[MAXDATELEN];
+    char lowstr[MAXDATELEN+1];
 
     tm->tm_year = 0;
     tm->tm_mon = 0;
@@ -170,14 +174,14 @@ timespan_in(char *str)
     fsec = 0;
 
     if (!PointerIsValid(str))
-       elog(WARN, "Bad (null) timespan external representation", NULL);
+       elog(WARN,"Bad (null) timespan external representation",NULL);
 
     if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
       || (DecodeDateDelta( field, ftype, nf, &dtype, tm, &fsec) != 0))
        elog(WARN,"Bad timespan external representation %s",str);
 
     if (!PointerIsValid(span = PALLOCTYPE(TimeSpan)))
-       elog(WARN, "Memory allocation failed, can't input timespan '%s'",str);
+       elog(WARN,"Memory allocation failed, can't input timespan '%s'",str);
 
     switch (dtype) {
     case DTK_DELTA:
@@ -189,7 +193,7 @@ timespan_in(char *str)
        break;
 
     default:
-       elog(WARN, "Internal coding error, can't input timespan '%s'",str);
+       elog(WARN,"Internal coding error, can't input timespan '%s'",str);
     };
 
     return(span);
@@ -205,7 +209,7 @@ timespan_out(TimeSpan *span)
 
     struct tm tt, *tm = &tt;
     double fsec;
-    char buf[MAXDATELEN];
+    char buf[MAXDATELEN+1];
 
     if (!PointerIsValid(span))
        return(NULL);
@@ -229,6 +233,26 @@ timespan_out(TimeSpan *span)
  *****************************************************************************/
 
 
+bool
+datetime_finite(DateTime *datetime)
+{
+    if (!PointerIsValid(datetime))
+       return FALSE;
+
+    return(! DATETIME_NOT_FINITE(*datetime));
+} /* datetime_finite() */
+
+
+bool
+timespan_finite(TimeSpan *timespan)
+{
+    if (!PointerIsValid(timespan))
+       return FALSE;
+
+    return(! TIMESPAN_NOT_FINITE(*timespan));
+} /* timespan_finite() */
+
+
 /*----------------------------------------------------------
  *  Relational operators for datetime.
  *---------------------------------------------------------*/
@@ -267,14 +291,14 @@ SetDateTime( DateTime dt) {
 
     if (DATETIME_IS_CURRENT(dt)) {
        GetCurrentTime(&tt);
-       dt = tm2datetime( &tt, 0, 0);
+       dt = tm2datetime( &tt, 0, NULL);
 
 #ifdef DATEDEBUG
 printf( "SetDateTime- current time is %f\n", dt);
 #endif
     } else { /* if (DATETIME_IS_EPOCH(dt1)) */
        GetEpochTime(&tt);
-       dt = tm2datetime( &tt, 0, 0);
+       dt = tm2datetime( &tt, 0, NULL);
 #ifdef DATEDEBUG
 printf( "SetDateTime- epoch time is %f\n", dt);
 #endif
@@ -520,7 +544,7 @@ TimeSpan *datetime_sub(DateTime *datetime1, DateTime *datetime2)
     dt2 = *datetime2;
 
     if (!PointerIsValid(result = PALLOCTYPE(TimeSpan)))
-       elog(WARN, "Memory allocation failed, can't subtract dates",NULL);
+       elog(WARN,"Memory allocation failed, can't subtract dates",NULL);
 
     if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
     if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
@@ -538,46 +562,83 @@ TimeSpan *datetime_sub(DateTime *datetime1, DateTime *datetime2)
 } /* datetime_sub() */
 
 
+/* datetime_add_span()
+ * Add a timespan to a datetime data type.
+ * Note that timespan 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.
+ */
 DateTime *datetime_add_span(DateTime *datetime, TimeSpan *span)
 {
     DateTime *result;
 
+#if FALSE
     double date, time;
     int year, mon, mday;
+#endif
 
     if ((!PointerIsValid(datetime)) || (!PointerIsValid(span)))
        return NULL;
 
     if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
-       elog(WARN, "Memory allocation failed, can't add dates",NULL);
+       elog(WARN,"Memory allocation failed, can't add dates",NULL);
 
 #ifdef DATEDEBUG
-printf( "date_add- add %f to %d %f\n", *datetime, span->month, span->time);
-#endif
-
-    *result = *datetime;
-    if (DATETIME_IS_RELATIVE(*result)) *result = SetDateTime(*result);
-
-    if (span->month != 0) {
-       time = JROUND(modf( (*result/86400), &date)*86400);
-       date += date2j(2000,1,1);
-
-       j2date( ((int) date), &year, &mon, &mday);
-       mon += span->month;
-       if (mon > 12) {
-           year += mon / 12;
-           mon %= 12;
-       } else if (mon < 0) {
-           year += mon / 12;
-           mon %= 12;
-           year -= 1;
-           mon += 12;
+printf( "datetime_add_span- add %f to %d %f\n", *datetime, span->month, span->time);
+#endif
+
+    if (DATETIME_NOT_FINITE(*datetime)) {
+       *result = *datetime;
+
+    } else if (TIMESPAN_IS_INVALID(*span)) {
+       DATETIME_INVALID(*result);
+
+    } else {
+       *result = (DATETIME_IS_RELATIVE(*datetime)? SetDateTime(*datetime): *datetime);
+
+       if (span->month != 0) {
+           struct tm tt, *tm = &tt;
+           double fsec;
+
+           if (datetime2tm( *result, NULL, tm, &fsec) == 0) {
+#ifdef DATEDEBUG
+printf( "datetime_add_span- date was %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday);
+#endif
+               tm->tm_mon += span->month;
+               if (tm->tm_mon > 12) {
+                   tm->tm_year += (tm->tm_mon / 12);
+                   tm->tm_mon = (tm->tm_mon % 12);
+               } 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 > mdays[ tm->tm_mon-1]) {
+                   if ((tm->tm_mon == 2) && isleap( tm->tm_year)) {
+                       tm->tm_mday = (mdays[ tm->tm_mon-1]+1);
+                   } else {
+                       tm->tm_mday = mdays[ tm->tm_mon-1];
+                   };
+               };
+
+#ifdef DATEDEBUG
+printf( "datetime_add_span- date becomes %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday);
+#endif
+               *result = tm2datetime( tm, fsec, NULL);
+
+           } else {
+               DATETIME_INVALID(*result);
+           };
        };
-       *result += ((date2j( year, mon, mday)-date2j(2000,1,1))*86400);
-       *result += time;
-    };
 
-    *result = JROUND(*result + span->time);
+#if FALSE
+       *result = JROUND(*result + span->time);
+#endif
+       *result += span->time;
+    };
 
     return(result);
 } /* datetime_add_span() */
@@ -607,13 +668,13 @@ TimeSpan *timespan_um(TimeSpan *timespan)
        return NULL;
 
     if (!PointerIsValid(result = PALLOCTYPE(TimeSpan)))
-       elog(WARN, "Memory allocation failed, can't subtract dates",NULL);
+       elog(WARN,"Memory allocation failed, can't subtract dates",NULL);
 
     result->time = -(timespan->time);
     result->month = -(timespan->month);
 
     return(result);
-} /* datetime_sub() */
+} /* timespan_um() */
 
 
 TimeSpan *timespan_add(TimeSpan *span1, TimeSpan *span2)
@@ -624,7 +685,7 @@ TimeSpan *timespan_add(TimeSpan *span1, TimeSpan *span2)
        return NULL;
 
     if (!PointerIsValid(result = PALLOCTYPE(TimeSpan)))
-       elog(WARN, "Memory allocation failed, can't add timespans",NULL);
+       elog(WARN,"Memory allocation failed, can't add timespans",NULL);
 
     result->month = (span1->month + span2->month);
     result->time = JROUND(span1->time + span2->time);
@@ -640,7 +701,7 @@ TimeSpan *timespan_sub(TimeSpan *span1, TimeSpan *span2)
        return NULL;
 
     if (!PointerIsValid(result = PALLOCTYPE(TimeSpan)))
-       elog(WARN, "Memory allocation failed, can't subtract timespans",NULL);
+       elog(WARN,"Memory allocation failed, can't subtract timespans",NULL);
 
     result->month = (span1->month - span2->month);
     result->time = JROUND(span1->time - span2->time);
@@ -654,6 +715,125 @@ TimeSpan *timespan_sub(TimeSpan *span1, TimeSpan *span2)
  *---------------------------------------------------------*/
 
 
+/* datetime_text()
+ * Convert datetime to text data type.
+ */
+text *
+datetime_text(DateTime *datetime)
+{
+    text *result;
+    char *str;
+    int len;
+
+    if (!PointerIsValid(datetime))
+       return NULL;
+
+    str = datetime_out(datetime);
+
+    if (!PointerIsValid(str))
+       return NULL;
+
+    len = (strlen(str)+VARHDRSZ);
+
+    if (!PointerIsValid(result = PALLOC(len)))
+       elog(WARN,"Memory allocation failed, can't convert datetime to text",NULL);
+
+    VARSIZE(result) = len;
+    memmove(VARDATA(result), str, (len-VARHDRSZ));
+
+    PFREE(str);
+
+    return(result);
+} /* datetime_text() */
+
+
+/* text_datetime()
+ * Convert text string to datetime.
+ * Text type is not null terminated, so use temporary string
+ *  then call the standard input routine.
+ */
+DateTime *
+text_datetime(text *str)
+{
+    DateTime *result;
+    int i;
+    char *sp, *dp, dstr[MAXDATELEN+1];
+
+    if (!PointerIsValid(str))
+       return NULL;
+
+    sp = VARDATA(str);
+    dp = dstr;
+    for (i = 0; i < (VARSIZE(str)-VARHDRSZ); i++) *dp++ = *sp++;
+    *dp = '\0';
+
+    result = datetime_in(dstr);
+
+    return(result);
+} /* text_datetime() */
+
+
+/* timespan_text()
+ * Convert timespan to text data type.
+ */
+text *
+timespan_text(TimeSpan *timespan)
+{
+    text *result;
+    char *str;
+    int len;
+
+    if (!PointerIsValid(timespan))
+       return NULL;
+
+    str = timespan_out(timespan);
+
+    if (!PointerIsValid(str))
+       return NULL;
+
+    len = (strlen(str)+VARHDRSZ);
+
+    if (!PointerIsValid(result = PALLOC(len)))
+       elog(WARN,"Memory allocation failed, can't convert timespan to text",NULL);
+
+    VARSIZE(result) = len;
+    memmove(VARDATA(result), str, (len-VARHDRSZ));
+
+    PFREE(str);
+
+    return(result);
+} /* timespan_text() */
+
+
+/* text_timespan()
+ * Convert text string to timespan.
+ * Text type may not be null terminated, so copy to temporary string
+ *  then call the standard input routine.
+ */
+TimeSpan *
+text_timespan(text *str)
+{
+    TimeSpan *result;
+    int i;
+    char *sp, *dp, dstr[MAXDATELEN+1];
+
+    if (!PointerIsValid(str))
+       return NULL;
+
+    sp = VARDATA(str);
+    dp = dstr;
+    for (i = 0; i < (VARSIZE(str)-VARHDRSZ); i++) *dp++ = *sp++;
+    *dp = '\0';
+
+    result = timespan_in(dstr);
+
+    return(result);
+} /* text_timespan() */
+
+
+/* datetime_part()
+ * Extract specified field from datetime.
+ */
 float64
 datetime_part(text *units, DateTime *datetime)
 {
@@ -662,7 +842,7 @@ datetime_part(text *units, DateTime *datetime)
     DateTime dt;
     int type, val;
     int i;
-    char *up, *lp, lowunits[MAXDATELEN];
+    char *up, *lp, lowunits[MAXDATELEN+1];
     double fsec;
     struct tm tt, *tm = &tt;
 
@@ -670,7 +850,7 @@ datetime_part(text *units, DateTime *datetime)
        return NULL;
 
     if (!PointerIsValid(result = PALLOCTYPE(float64data)))
-       elog(WARN, "Memory allocation failed, can't get date part",NULL);
+       elog(WARN,"Memory allocation failed, can't get date part",NULL);
 
     up = VARDATA(units);
     lp = lowunits;
@@ -694,7 +874,7 @@ printf( "datetime_part- units %s type=%d value=%d\n", lowunits, type, val);
 
        dt = (DATETIME_IS_RELATIVE(*datetime)? SetDateTime(*datetime): *datetime); 
 
-       if (datetime2tm( dt, tm, &fsec) == 0) {
+       if (datetime2tm( dt, &CTimeZone, tm, &fsec) == 0) {
            switch (val) {
            case DTK_TZ:
                *result = CTimeZone;
@@ -768,6 +948,9 @@ printf( "datetime_part- units %s type=%d value=%d\n", lowunits, type, val);
 } /* datetime_part() */
 
 
+/* timespan_part()
+ * Extract specified field from timespan.
+ */
 float64
 timespan_part(text *units, TimeSpan *timespan)
 {
@@ -775,7 +958,7 @@ timespan_part(text *units, TimeSpan *timespan)
 
     int type, val;
     int i;
-    char *up, *lp, lowunits[MAXDATELEN];
+    char *up, *lp, lowunits[MAXDATELEN+1];
     double fsec;
     struct tm tt, *tm = &tt;
 
@@ -783,7 +966,7 @@ timespan_part(text *units, TimeSpan *timespan)
        return NULL;
 
     if (!PointerIsValid(result = PALLOCTYPE(float64data)))
-       elog(WARN, "Memory allocation failed, can't get date part",NULL);
+       elog(WARN,"Memory allocation failed, can't get date part",NULL);
 
     up = VARDATA(units);
     lp = lowunits;
@@ -879,10 +1062,6 @@ printf( "timespan_part- units %s type=%d value=%d\n", lowunits, type, val);
  *   PRIVATE ROUTINES                                                        *
  *****************************************************************************/
 
-#if USE_NEW_TIME_CODE
-#define DATE_MAXLEN    47
-#endif
-
 /* definitions for squeezing values into "value" */
 #define ABS_SIGNBIT    0200
 #define VALMASK                0177
@@ -1218,11 +1397,12 @@ int j2day( int date)
  * Also, month is one-based, _not_ zero-based.
  */
 int
-datetime2tm( DateTime dt, struct tm *tm, double *fsec)
+datetime2tm( DateTime dt, int *tzp, struct tm *tm, double *fsec)
 {
     double date, time, sec;
 
-    time = (modf( dt2local( dt, CTimeZone)/86400, &date)*86400);
+    if (tzp != NULL) dt = dt2local( dt, *tzp);
+    time = (modf( dt/86400, &date)*86400);
     date += date2j(2000,1,1);
     if (time < 0) {
            time += 86400;
@@ -1233,7 +1413,8 @@ datetime2tm( DateTime dt, struct tm *tm, double *fsec)
     if (date < 0) return -1;
 
 #ifdef DATEDEBUG
-printf( "datetime2tm- date is %f (%f %f)\n", dt, date, time);
+printf( "datetime2tm- date is %f (%f %f)\n",
+ ((tzp != NULL)? dt2local(dt, -(*tzp)): dt), date, time);
 #endif
 
     j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
@@ -1254,8 +1435,8 @@ printf( "datetime2tm- time is %02d:%02d:%02d %.7f\n", tm->tm_hour, tm->tm_min, t
     tm->tm_isdst = -1;
 
 #ifdef DATEDEBUG
-printf( "datetime2tm- timezone is %s; offset is %d; daylight is %d\n",
- CTZName, CTimeZone, CDayLight);
+printf( "datetime2tm- timezone is %s; offset is %d (%d); daylight is %d\n",
+ CTZName, ((tzp != NULL)? *tzp: 0), CTimeZone, CDayLight);
 #endif
 
     return 0;
@@ -1268,7 +1449,7 @@ printf( "datetime2tm- timezone is %s; offset is %d; daylight is %d\n",
  * Also, month is one-based, _not_ zero-based.
  */
 DateTime
-tm2datetime( struct tm *tm, double fsec, int tzp) {
+tm2datetime( struct tm *tm, double fsec, int *tzp) {
 
     DateTime result;
     double date, time;
@@ -1284,7 +1465,7 @@ tm2datetime( struct tm *tm, double fsec, int tzp) {
 printf( "tm2datetime- date is %f (%f %f %d)\n", result, date, time, (((tm->tm_hour*60)+tm->tm_min)*60+tm->tm_sec));
 printf( "tm2datetime- time is %f %02d:%02d:%02d %f\n", time, tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
 #endif
-    if (tzp != 0) result = dt2local(result, -tzp);
+    if (tzp != NULL) result = dt2local(result, -(*tzp));
 
     return(result);
 } /* tm2datetime() */
@@ -1832,40 +2013,17 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm *tm)
 
     *tmask = 0;
 
+    /* look first for text fields, since that will be unambiguous month */
     for (i = 0; i < nf; i++) {
-       str = field[i];
-       len = strlen(str);
-
-       if (len <= 0)
-           return -1;
-
-       if (isdigit(*str)) {
-           if (DecodeNumber( len, str, fmask, &dmask, tm, &fsec) != 0)
-               return -1;
-
-       } else if (isalpha(*str)) {
+       if (isalpha(*field[i])) {
            type = DecodeSpecial( i, field[i], &val);
            if (type == IGNORE) continue;
 
            dmask = DTK_M(type);
            switch (type) {
-           case YEAR:
-#ifdef DATEDEBUG
-printf( "DecodeDate- year field %s value is %d\n", field[i], val); 
-#endif
-               tm->tm_mon = val;
-               break;
-
            case MONTH:
 #ifdef DATEDEBUG
 printf( "DecodeDate- month field %s value is %d\n", field[i], val); 
-#endif
-               tm->tm_mon = val;
-               break;
-
-           case DAY:
-#ifdef DATEDEBUG
-printf( "DecodeDate- month field %s value is %d\n", field[i], val); 
 #endif
                tm->tm_mon = val;
                break;
@@ -1876,7 +2034,25 @@ printf( "DecodeDate- illegal field %s value is %d\n", field[i], val);
 #endif
                return -1;
            };
+           if (fmask & dmask) return -1;
+
+           fmask |= dmask;
+           *tmask |= dmask;
+
+           /* mark this field as being completed */
+           field[i] = NULL;
        };
+    };
+
+    /* now pick up remaining numeric fields */
+    for (i = 0; i < nf; i++) {
+       if (field[i] == NULL) continue;
+
+       if ((len = strlen(field[i])) <= 0)
+           return -1;
+
+       if (DecodeNumber( len, field[i], fmask, &dmask, tm, &fsec) != 0)
+           return -1;
 
        if (fmask & dmask) return -1;
 
@@ -1955,6 +2131,19 @@ printf( "DecodeNumber- %s is %d fmask=%08x tmask=%08x\n", str, val, fmask, *tmas
 printf( "DecodeNumber- match %d (%s) as year\n", val, str);
 #endif
        *tmask = DTK_M(YEAR);
+
+       /* already have a year? then see if we can substitute... */
+       if (fmask & DTK_M(YEAR)) {
+           if ((!(fmask & DTK_M(DAY)))
+            && ((tm->tm_year >= 1) && (tm->tm_year <= 31))) {
+#ifdef DATEDEBUG
+printf( "DecodeNumber- misidentified year previously; swap with day %d\n", tm->tm_mday);
+#endif
+               tm->tm_mday = tm->tm_year;
+               *tmask = DTK_M(DAY);
+           };
+       };
+
        tm->tm_year = val;
 
     /* special case day of year? */
@@ -1966,7 +2155,7 @@ printf( "DecodeNumber- match %d (%s) as year\n", val, str);
          &tm->tm_year,&tm->tm_mon,&tm->tm_mday);
 
     /* already have year? then could be month */
-    } else if ((fmask && DTK_M(YEAR)) && (! (fmask & DTK_M(MONTH)))
+    } else if ((fmask & DTK_M(YEAR)) && (! (fmask & DTK_M(MONTH)))
       && ((val >= 1) && (val <= 12))) {
 #ifdef DATEDEBUG
 printf( "DecodeNumber- match %d (%s) as month\n", val, str);
@@ -1975,11 +2164,7 @@ printf( "DecodeNumber- match %d (%s) as month\n", val, str);
        tm->tm_mon = val;
 
     /* no year and EuroDates enabled? then could be day */
-#if USE_EURODATES
     } else if ((EuroDates || (fmask & DTK_M(MONTH)))
-#else
-    } else if ((fmask & DTK_M(MONTH))
-#endif
       && (! ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(DAY))))
       && ((val >= 1) && (val <= 31))) {
 #ifdef DATEDEBUG
@@ -1996,6 +2181,14 @@ printf( "DecodeNumber- (2) match %d (%s) as month\n", val, str);
        *tmask = DTK_M(MONTH);
        tm->tm_mon = val;
 
+    } else if ((! (fmask & DTK_M(DAY)))
+      && ((val >= 1) && (val <= 31))) {
+#ifdef DATEDEBUG
+printf( "DecodeNumber- (2) match %d (%s) as day\n", val, str);
+#endif
+       *tmask = DTK_M(DAY);
+       tm->tm_mday = val;
+
     } else if (! (fmask & DTK_M(YEAR))) {
 #ifdef DATEDEBUG
 printf( "DecodeNumber- (2) match %d (%s) as year\n", val, str);
@@ -2467,7 +2660,7 @@ int EncodeDateTime(struct tm *tm, double fsec, int style, char *str)
     int day, hour, min;
     double sec;
 #ifdef DATEDEBUG
-    char buf[MAXDATELEN];
+    char buf[MAXDATELEN+1];
 #endif
 
     sec = (tm->tm_sec + fsec);
index 3ae1978b73615645790208a6a24053cdc689f72a..8f1420bbd2d491d21af61e2765f4855cdfab402f 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.21 1997/03/28 07:12:53 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.22 1997/04/02 18:33:50 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,7 @@
 #ifndef USE_POSIX_TIME
 #include <sys/timeb.h>
 #endif
+#include "utils/builtins.h"
 #include "access/xact.h"
 
 
@@ -90,11 +91,19 @@ printf( "GetCurrentAbsoluteTime- timezone is %s -> %d seconds from UTC\n",
 void
 GetCurrentTime(struct tm *tm)
 {
-    time_t now;
+    abstime2tm( GetCurrentTransactionStartTime(), &CTimeZone, tm);
+
+    return;
+} /* GetCurrentTime() */
+
+
+void
+abstime2tm(AbsoluteTime time, int *tzp, struct tm *tm)
+{
     struct tm *tt;
 
-    now = GetCurrentTransactionStartTime()-CTimeZone;
-    tt = gmtime( &now);
+    if (tzp != NULL) time -= *tzp;
+    tt = gmtime((time_t *) &time);
 
     tm->tm_year = tt->tm_year+1900;
     tm->tm_mon = tt->tm_mon+1;
@@ -105,11 +114,13 @@ GetCurrentTime(struct tm *tm)
     tm->tm_isdst = tt->tm_isdst;
 
     return;
-} /* GetCurrentTime() */
+} /* abstime2tm() */
 
 
-AbsoluteTime tm2abstime( struct tm *tm, int tz);
-
+/* tm2abstime()
+ * Convert a tm structure to abstime.
+ * Note that tm has full year (not 1900-based) and 1-based month.
+ */
 AbsoluteTime
 tm2abstime( struct tm *tm, int tz)
 {
@@ -122,13 +133,13 @@ tm2abstime( struct tm *tm, int tz)
       || tm->tm_hour < 0 || tm->tm_hour >= 24
       || tm->tm_min < 0 || tm->tm_min > 59
       || tm->tm_sec < 0 || tm->tm_sec > 59)
-       return INVALID_ABSTIME;
+       return(INVALID_ABSTIME);
 
     day = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j( 1970, 1, 1));
 
     /* check for time out of range */
     if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
-       return INVALID_ABSTIME;
+       return(INVALID_ABSTIME);
 
     /* convert to seconds */
     sec = tm->tm_sec + tz + (tm->tm_min +(day*24 + tm->tm_hour)*60)*60;
@@ -136,7 +147,7 @@ tm2abstime( struct tm *tm, int tz)
     /* check for overflow */
     if ((day == MAX_DAYNUM && sec < 0) ||
       (day == MIN_DAYNUM && sec > 0))
-       return INVALID_ABSTIME;
+       return(INVALID_ABSTIME);
 
     /* daylight correction */
     if (tm->tm_isdst < 0) {            /* unknown; find out */
@@ -147,7 +158,7 @@ tm2abstime( struct tm *tm, int tz)
 
     /* check for reserved values (e.g. "current" on edge of usual range */
     if (!AbsoluteTimeIsReal(sec))
-       return INVALID_ABSTIME;
+       return(INVALID_ABSTIME);
 
     return sec;
 } /* tm2abstime() */
@@ -369,6 +380,16 @@ AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2)
 }
 
 
+/* abstime_finite()
+ */
+bool
+abstime_finite(AbsoluteTime abstime)
+{
+    return((abstime != INVALID_ABSTIME)
+      && (abstime != NOSTART_ABSTIME) && (abstime != NOEND_ABSTIME));
+} /* abstime_datetime() */
+
+
 /*
  *     abstimeeq       - returns 1, iff arguments are equal
  *     abstimene       - returns 1, iff arguments are not equal
@@ -381,7 +402,7 @@ bool
 abstimeeq(AbsoluteTime t1, AbsoluteTime t2)
 {
     if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
-       return 0;
+       return(FALSE);
     if (t1 == CURRENT_ABSTIME)
        t1 = GetCurrentTransactionStartTime();
     if (t2 == CURRENT_ABSTIME)
@@ -394,7 +415,7 @@ bool
 abstimene(AbsoluteTime t1, AbsoluteTime t2)
 { 
     if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
-       return 0;
+       return(FALSE);
     if (t1 == CURRENT_ABSTIME)
        t1 = GetCurrentTransactionStartTime();
     if (t2 == CURRENT_ABSTIME)
@@ -407,7 +428,7 @@ bool
 abstimelt(AbsoluteTime t1, AbsoluteTime t2)
 { 
     if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
-       return 0;
+       return(FALSE);
     if (t1 == CURRENT_ABSTIME)
        t1 = GetCurrentTransactionStartTime();
     if (t2 == CURRENT_ABSTIME)
@@ -420,7 +441,7 @@ bool
 abstimegt(AbsoluteTime t1, AbsoluteTime t2)
 { 
     if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
-       return 0;
+       return(FALSE);
     if (t1 == CURRENT_ABSTIME)
        t1 = GetCurrentTransactionStartTime();
     if (t2 == CURRENT_ABSTIME)
@@ -433,7 +454,7 @@ bool
 abstimele(AbsoluteTime t1, AbsoluteTime t2)
 { 
     if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
-       return 0;
+       return(FALSE);
     if (t1 == CURRENT_ABSTIME)
        t1 = GetCurrentTransactionStartTime();
     if (t2 == CURRENT_ABSTIME)
@@ -446,7 +467,7 @@ bool
 abstimege(AbsoluteTime t1, AbsoluteTime t2)
 { 
     if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
-       return 0;
+       return(FALSE);
     if (t1 == CURRENT_ABSTIME)
        t1 = GetCurrentTransactionStartTime();
     if (t2 == CURRENT_ABSTIME)
@@ -455,6 +476,7 @@ abstimege(AbsoluteTime t1, AbsoluteTime t2)
     return(t1 >= t2);
 }
 
+
 /* datetime_abstime()
  * Convert datetime to abstime.
  */
@@ -480,10 +502,10 @@ datetime_abstime(DateTime *datetime)
 
     } else {
        if (DATETIME_IS_RELATIVE(*datetime)) {
-           datetime2tm( SetDateTime(*datetime), tm, &fsec);
+           datetime2tm( SetDateTime(*datetime), &CTimeZone, tm, &fsec);
            result = tm2abstime( tm, 0);
 
-       } else if (datetime2tm( *datetime, tm, &fsec) == 0) {
+       } else if (datetime2tm( *datetime, &CTimeZone, tm, &fsec) == 0) {
            result = tm2abstime( tm, 0);
 
        } else {
@@ -493,3 +515,42 @@ datetime_abstime(DateTime *datetime)
 
     return(result);
 } /* datetime_abstime() */
+
+/* abstime_datetime()
+ * Convert datetime to abstime.
+ */
+DateTime *
+abstime_datetime(AbsoluteTime abstime)
+{
+    DateTime *result;
+
+    if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
+       elog(WARN,"Unable to allocate space to convert abstime to datetime",NULL);
+
+    switch (abstime) {
+    case INVALID_ABSTIME:
+        DATETIME_INVALID(*result);
+       break;
+
+    case NOSTART_ABSTIME:
+        DATETIME_NOBEGIN(*result);
+       break;
+
+    case NOEND_ABSTIME:
+        DATETIME_NOEND(*result);
+       break;
+
+    case EPOCH_ABSTIME:
+        DATETIME_EPOCH(*result);
+       break;
+
+    case CURRENT_ABSTIME:
+        DATETIME_CURRENT(*result);
+       break;
+
+    default:
+        *result = abstime + ((date2j( 1970, 1, 1) - date2j( 2000, 1, 1))*86400);
+    };
+
+    return(result);
+} /* abstime_datetime() */
index 641dff80e0924610aa3d4be8742cba210bfb9390..99c7d0f70f09138b9319eab4c2e2e8bb927606a1 100644 (file)
@@ -88,3 +88,23 @@ timestampge(time_t t1, time_t t2)
 {
     return difftime(t1, t2) <= 0;
 }
+
+DateTime *
+timestamp_datetime(time_t timestamp)
+{
+    DateTime *result;
+
+    double fsec = 0;
+    struct tm *tm;
+
+    if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
+       elog(WARN,"Memory allocation failed, can't convert timestamp to datetime",NULL);
+
+    tm = localtime((time_t *) &timestamp);
+    tm->tm_year += 1900;
+    tm->tm_mon += 1;
+
+    *result = tm2datetime(tm, fsec, NULL);
+
+    return(result);
+} /* timestamp_datetime() */
index e5db0259aea881efd01e9c62a6a90c0189ce225f..b2d9b4afb994b9f696a3607bd1f8651ce0f53d26 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_aggregate.h,v 1.3 1996/11/14 21:39:07 scrappy Exp $
+ * $Id: pg_aggregate.h,v 1.4 1997/04/02 18:36:09 scrappy Exp $
  *
  * NOTES
  *    the genbki.sh script reads this file and generates .bki
@@ -87,29 +87,33 @@ typedef FormData_pg_aggregate       *Form_pg_aggregate;
  * ---------------
  */
 
-DATA(insert OID = 0 ( avg   PGUID int4pl  int4inc  int4div  23  23  23  23 0  0 ));
-DATA(insert OID = 0 ( avg   PGUID int2pl  int2inc  int2div  21  21  21  21  0  0 ));
-DATA(insert OID = 0 ( avg PGUID float4pl float4inc float4div  700  700  700  700 0.0 0.0 ));
-DATA(insert OID = 0 ( avg PGUID float8pl float8inc float8div  701  701  701  701 0.0 0.0 ));
-
-DATA(insert OID = 0 ( sum   PGUID int4pl   - -  23  23  0  23  0   _null_ ));
-DATA(insert OID = 0 ( sum   PGUID int2pl   - -  21  21  0  21  0   _null_ ));
-DATA(insert OID = 0 ( sum PGUID float4pl - - 700  700 0  700  0.0 _null_ ));
-DATA(insert OID = 0 ( sum PGUID float8pl - - 701  701 0  701  0.0 _null_ ));
-
-DATA(insert OID = 0 ( max   PGUID int4larger   - -  23  23  0  23  _null_ _null_ ));
-DATA(insert OID = 0 ( max   PGUID int2larger   - -  21  21  0  21  _null_ _null_ ));
-DATA(insert OID = 0 ( max PGUID float4larger - - 700  700 0  700  _null_ _null_ ));
-DATA(insert OID = 0 ( max PGUID float8larger - - 701  701 0  701  _null_ _null_ ));
-DATA(insert OID = 0 ( max PGUID date_larger  - - 1082 1082 0 1082 _null_ _null_ ));
-
-DATA(insert OID = 0 ( min   PGUID int4smaller   - -  23  23  0  23  _null_ _null_ ));
-DATA(insert OID = 0 ( min   PGUID int2smaller   - -  21  21  0  21    _null_ _null_ ));
-DATA(insert OID = 0 ( min PGUID float4smaller - - 700  700 0  700   _null_ _null_ ));
-DATA(insert OID = 0 ( min PGUID float8smaller - - 701  701 0  701  _null_ _null_ ));
-DATA(insert OID = 0 ( min PGUID date_smaller  - - 1082 1082 0 1082 _null_ _null_ ));
-
-DATA(insert OID = 0 ( count     PGUID - int4inc - 0 0 23 23  _null_ 0 ));
+DATA(insert OID = 0 ( avg   PGUID int4pl   int4inc   int4div  23  23  23  23 0  0 ));
+DATA(insert OID = 0 ( avg   PGUID int2pl   int2inc   int2div  21  21  21  21  0  0 ));
+DATA(insert OID = 0 ( avg   PGUID float4pl float4inc float4div  700  700  700  700 0.0 0.0 ));
+DATA(insert OID = 0 ( avg   PGUID float8pl float8inc float8div  701  701  701  701 0.0 0.0 ));
+
+DATA(insert OID = 0 ( sum   PGUID int4pl   - -   23  23  0  23  0   _null_ ));
+DATA(insert OID = 0 ( sum   PGUID int2pl   - -   21  21  0  21  0   _null_ ));
+DATA(insert OID = 0 ( sum   PGUID float4pl - -  700  700 0  700 0.0 _null_ ));
+DATA(insert OID = 0 ( sum   PGUID float8pl - -  701  701 0  701 0.0 _null_ ));
+
+DATA(insert OID = 0 ( max   PGUID int4larger    - -   23   23 0   23 _null_ _null_ ));
+DATA(insert OID = 0 ( max   PGUID int2larger    - -   21   21 0   21 _null_ _null_ ));
+DATA(insert OID = 0 ( max   PGUID float4larger  - -  700  700 0  700 _null_ _null_ ));
+DATA(insert OID = 0 ( max   PGUID float8larger  - -  701  701 0  701 _null_ _null_ ));
+DATA(insert OID = 0 ( max   PGUID int4larger    - -  702  702 0  702 _null_ _null_ ));
+DATA(insert OID = 0 ( max   PGUID date_larger   - - 1082 1082 0 1082 _null_ _null_ ));
+DATA(insert OID = 0 ( max   PGUID float8larger  - - 1084 1084 0 1084 _null_ _null_ ));
+
+DATA(insert OID = 0 ( min   PGUID int4smaller   - -   23   23 0   23 _null_ _null_ ));
+DATA(insert OID = 0 ( min   PGUID int2smaller   - -   21   21 0   21 _null_ _null_ ));
+DATA(insert OID = 0 ( min   PGUID float4smaller - -  700  700 0  700 _null_ _null_ ));
+DATA(insert OID = 0 ( min   PGUID float8smaller - -  701  701 0  701 _null_ _null_ ));
+DATA(insert OID = 0 ( min   PGUID int4smaller   - -  702  702 0  702 _null_ _null_ ));
+DATA(insert OID = 0 ( min   PGUID date_smaller  - - 1082 1082 0 1082 _null_ _null_ ));
+DATA(insert OID = 0 ( min   PGUID float8smaller - - 1084 1084 0 1084 _null_ _null_ ));
+
+DATA(insert OID = 0 ( count PGUID - int4inc - 0 0 23 23  _null_ 0 ));
 
 /*
  * prototypes for fucnctions in pg_aggregate.c
index 681c9b54f85328f19e54858f71cd14c3d940ff6c..04e826b0f2cae71548f4d73b9b7b396f5183b922 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_operator.h,v 1.6 1997/03/25 08:10:37 scrappy Exp $
+ * $Id: pg_operator.h,v 1.7 1997/04/02 18:36:12 scrappy Exp $
  *
  * NOTES
  *    the genbki.sh script reads this file and generates .bki
@@ -413,6 +413,7 @@ DATA(insert OID = 1325 (  ">="     PGUID 0 b t f 1184 1184   16 1322 1322 0 0 da
 
 DATA(insert OID = 1327 (  "+"      PGUID 0 b t f 1184 1186 1184 1327    0 0 0 datetime_add_span - - ));
 DATA(insert OID = 1328 (  "-"      PGUID 0 b t f 1184 1184 1186    0    0 0 0 datetime_sub - - ));
+DATA(insert OID = 1329 (  "-"      PGUID 0 b t f 1184 1186 1184    0    0 0 0 datetime_sub_span - - ));
 
 /* timespan operators */
 DATA(insert OID = 1330 (  "="      PGUID 0 b t f 1186 1186   16 1330 1331 1332 1332 timespan_eq eqsel eqjoinsel ));
@@ -422,7 +423,7 @@ DATA(insert OID = 1333 (  "<="     PGUID 0 b t f 1186 1186   16 1334 1334 0 0 ti
 DATA(insert OID = 1334 (  ">"      PGUID 0 b t f 1186 1186   16 1333 1333 0 0 timespan_gt intltsel intltjoinsel ));
 DATA(insert OID = 1335 (  ">="     PGUID 0 b t f 1186 1186   16 1332 1332 0 0 timespan_ge intltsel intltjoinsel ));
 
-DATA(insert OID = 1336 (  "-"      PGUID 0 b t f    0 1186 1186    0    0 0 0 timespan_um 0 0 ));
+DATA(insert OID = 1336 (  "-"      PGUID 0 l t f    0 1186 1186    0    0 0 0 timespan_um 0 0 ));
 DATA(insert OID = 1337 (  "+"      PGUID 0 b t f 1186 1186 1186 1337    0 0 0 timespan_add - - ));
 DATA(insert OID = 1338 (  "-"      PGUID 0 b t f 1186 1186 1186    0    0 0 0 timespan_sub - - ));
 
index 1d8da6905199028fc860f6c12ed26a2d4091c2d7..e8db3a263eb29dda0a0aebd03aea0b6e686943e8 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.15 1997/04/02 03:29:37 vadim Exp $
+ * $Id: pg_proc.h,v 1.16 1997/04/02 18:36:24 scrappy Exp $
  *
  * NOTES
  *    The script catalog/genbki.sh reads this file and generates .bki
@@ -337,6 +337,7 @@ DATA(insert OID = 271 (  intervallenge     PGUID 11 f t f 2 f 16 "704 703" 100 0
 DATA(insert OID = 272 (  intervalstart     PGUID 11 f t f 1 f 702 "704" 100 0 0 100  foo bar ));
 DATA(insert OID = 273 (  intervalend       PGUID 11 f t f 1 f 702 "704" 100 0 0 100  foo bar ));
 DATA(insert OID = 274 (  timeofday         PGUID 11 f t f 0 f 25 "0" 100 0 0 100  foo bar ));
+DATA(insert OID = 275 (  abstime_finite    PGUID 11 f t f 1 f 16 "702" 100 0 0 100  foo bar ));
 
 DATA(insert OID = 276 (  int2fac           PGUID 11 f t f 1 f 21 "21" 100 0 0 100  foo bar ));
 DATA(insert OID = 279 (  float48mul        PGUID 11 f t f 2 f 701 "700 701" 100 0 0 100  foo bar ));
@@ -754,7 +755,9 @@ DATA(insert OID = 1154 (  datetime_lt      PGUID 11 f t f 2 f 16 "1184 1184" 100
 DATA(insert OID = 1155 (  datetime_le      PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100  foo bar ));
 DATA(insert OID = 1156 (  datetime_ge      PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100  foo bar ));
 DATA(insert OID = 1157 (  datetime_gt      PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100  foo bar ));
-/* reserve OIDs 1158-1159 for additional date/time conversion routines! tgl 97/03/19 */
+DATA(insert OID = 1158 (  datetime_finite  PGUID 11 f t f 1 f 16 "1184" 100 0 0 100  foo bar ));
+/* reserve OIDs 1158 for additional date/time conversion routines! tgl 97/03/19 */
+
 DATA(insert OID = 1160 (  timespan_in      PGUID 11 f t f 1 f 1186 "0" 100 0 0 100  foo bar ));
 DATA(insert OID = 1161 (  timespan_out     PGUID 11 f t f 1 f 23 "0" 100 0 0 100  foo bar ));
 DATA(insert OID = 1162 (  timespan_eq      PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100  foo bar ));
@@ -768,11 +771,24 @@ DATA(insert OID = 1169 (  timespan_add     PGUID 11 f t f 2 f 1186 "1186 1186" 1
 DATA(insert OID = 1170 (  timespan_sub     PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100  foo bar ));
 DATA(insert OID = 1171 (  datetime_part    PGUID 11 f t f 2 f  701 "25 1184" 100 0 0 100  foo bar ));
 DATA(insert OID = 1172 (  timespan_part    PGUID 11 f t f 2 f  701 "25 1186" 100 0 0 100  foo bar ));
-/* reserve OIDs 1173-1180 for additional date/time conversion routines! tgl 97/03/19 */
-DATA(insert OID = 1188 (  datetime_sub      PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100  foo bar ));
-DATA(insert OID = 1189 (  datetime_add_span PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100  foo bar ));
-DATA(insert OID = 1190 (  datetime_sub_span PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100  foo bar ));
-/* reserve OIDs 1191-1199 for additional date/time conversion routines! tgl 97/03/19 */
+
+DATA(insert OID = 1173 (  abstime_datetime   PGUID 11 f t f 1 f 1184  "702" 100 0 0 100  foo bar ));
+DATA(insert OID = 1174 (  date_datetime      PGUID 11 f t f 1 f 1184 "1082" 100 0 0 100  foo bar ));
+DATA(insert OID = 1175 (  timestamp_datetime PGUID 11 f t f 1 f 1184 "1296" 100 0 0 100  foo bar ));
+DATA(insert OID = 1176 (  datetime_datetime  PGUID 11 f t f 2 f 1184 "1082 1083" 100 0 0 100  foo bar ));
+DATA(insert OID = 1177 (  reltime_timespan   PGUID 11 f t f 1 f 1186  "703" 100 0 0 100  foo bar ));
+DATA(insert OID = 1178 (  datetime_date      PGUID 11 f t f 1 f 1082 "1184" 100 0 0 100  foo bar ));
+DATA(insert OID = 1179 (  abstime_date       PGUID 11 f t f 1 f 1082  "702" 100 0 0 100  foo bar ));
+DATA(insert OID = 1180 (  datetime_abstime   PGUID 11 f t f 1 f  702 "1184" 100 0 0 100  foo bar ));
+
+DATA(insert OID = 1188 (  datetime_sub       PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100  foo bar ));
+DATA(insert OID = 1189 (  datetime_add_span  PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100  foo bar ));
+DATA(insert OID = 1190 (  datetime_sub_span  PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100  foo bar ));
+DATA(insert OID = 1191 (  text_datetime      PGUID 11 f t f 1 f 1184 "25" 100 0 0 100  foo bar ));
+DATA(insert OID = 1192 (  datetime_text      PGUID 11 f t f 1 f   25 "1184" 100 0 0 100  foo bar ));
+DATA(insert OID = 1193 (  timespan_text      PGUID 11 f t f 1 f 1186 "25" 100 0 0 100  foo bar ));
+DATA(insert OID = 1194 (  timespan_reltime   PGUID 11 f t f 1 f  703 "1186" 100 0 0 100  foo bar ));
+/* reserve OIDs 1195-1199 for additional date/time conversion routines! tgl 97/03/19 */
 
 DATA(insert OID = 1200 (  int42reltime     PGUID 11 f t f 1 f 703 "21" 100 0 0 100  foo bar ));
 
@@ -788,6 +804,7 @@ DATA(insert OID = 1238 (  texticregexeq    PGUID 11 f t f 2 f 16 "25 25" 100 0 1
 DATA(insert OID = 1239 (  texticregexne    PGUID 11 f t f 2 f 16 "25 25" 100 0 1 0  foo bar ));
 DATA(insert OID = 1240 (  nameicregexeq    PGUID 11 f t f 2 f 16 "19 25" 100 0 0 100  foo bar ));
 DATA(insert OID = 1241 (  nameicregexne    PGUID 11 f t f 2 f 16 "19 25" 100 0 0 100  foo bar ));
+
 DATA(insert OID = 1297 (  timestamp_in     PGUID 11 f t f 1 f 1296 "0" 100 0 0 100  foo bar ));
 DATA(insert OID = 1298 (  timestamp_out    PGUID 11 f t f 1 f 23 "0" 100 0 0 100  foo bar ));
 DATA(insert OID = 1299 (  now              PGUID 11 f t f 0 f 1296 "0" 100 0 0 100  foo bar ));
@@ -797,26 +814,73 @@ DATA(insert OID = 1308 (  timestamplt      PGUID 11 f t f 2 f 16 "1296 1296" 100
 DATA(insert OID = 1309 (  timestampgt      PGUID 11 f t f 2 f 16 "1296 1296" 100 0 0 100  foo bar ));
 DATA(insert OID = 1310 (  timestample      PGUID 11 f t f 2 f 16 "1296 1296" 100 0 0 100  foo bar ));
 DATA(insert OID = 1311 (  timestampge      PGUID 11 f t f 2 f 16 "1296 1296" 100 0 0 100  foo bar ));
-
+/* reserve OIDs 1312-1319 for additional date/time conversion routines! tgl 97/04/01 */
+
+DATA(insert OID = 1340 (  text         PGUID 14 f t f 1 f   25 "1184" 100 0 0 100  "select datetime_text($1)" - ));
+DATA(insert OID = 1341 (  text         PGUID 14 f t f 1 f   25 "1186" 100 0 0 100  "select timespan_text($1)" - ));
+/* reserve OIDs 1339-1349 for additional date/time conversion routines! tgl 97/04/01 */
+
+DATA(insert OID = 1350 (  datetime     PGUID 14 f t f 1 f 1184 "1184" 100 0 0 100  "select $1" - ));
+DATA(insert OID = 1351 (  datetime     PGUID 14 f t f 1 f 1184   "25" 100 0 0 100  "select text_datetime($1)" - ));
+DATA(insert OID = 1352 (  datetime     PGUID 14 f t f 1 f 1184  "702" 100 0 0 100  "select abstime_datetime($1)" - ));
+DATA(insert OID = 1353 (  datetime     PGUID 14 f t f 1 f 1184 "1082" 100 0 0 100  "select date_datetime($1)" - ));
+DATA(insert OID = 1354 (  datetime     PGUID 14 f t f 1 f 1184 "1296" 100 0 0 100  "select timestamp_datetime($1)" - ));
+DATA(insert OID = 1355 (  datetime     PGUID 14 f t f 2 f 1184 "1082 1083" 100 0 0 100  "select datetime_datetime($1, $2)" - ));
+DATA(insert OID = 1356 (  timespan     PGUID 14 f t f 1 f 1186 "1186" 100 0 0 100  "select $1" - ));
+DATA(insert OID = 1357 (  timespan     PGUID 14 f t f 1 f 1186  "703" 100 0 0 100  "select reltime_timespan($1)" - ));
+DATA(insert OID = 1358 (  timespan     PGUID 14 f t f 1 f 1186 "1083" 100 0 0 100  "select time_timespan($1)" - ));
+DATA(insert OID = 1359 (  date         PGUID 14 f t f 1 f 1082 "1082" 100 0 0 100  "select $1" - ));
+DATA(insert OID = 1360 (  date         PGUID 14 f t f 1 f 1082 "1184" 100 0 0 100  "select datetime_date($1)" - ));
+DATA(insert OID = 1361 (  date         PGUID 14 f t f 1 f 1082  "702" 100 0 0 100  "select abstime_date($1)" - ));
+DATA(insert OID = 1362 (  time         PGUID 14 f t f 1 f 1083 "1083" 100 0 0 100  "select $1" - ));
+DATA(insert OID = 1363 (  time         PGUID 14 f t f 1 f 1083 "1184" 100 0 0 100  "select datetime_time($1)" - ));
+DATA(insert OID = 1364 (  time         PGUID 14 f t f 1 f 1083  "702" 100 0 0 100  "select abstime_time($1)" - ));
+DATA(insert OID = 1365 (  abstime      PGUID 14 f t f 1 f  702  "702" 100 0 0 100  "select $1" - ));
+DATA(insert OID = 1366 (  abstime      PGUID 14 f t f 1 f  702 "1184" 100 0 0 100  "select datetime_abstime($1)" - ));
+DATA(insert OID = 1367 (  reltime      PGUID 14 f t f 1 f  703  "703" 100 0 0 100  "select $1" - ));
+DATA(insert OID = 1368 (  reltime      PGUID 14 f t f 1 f  703 "1186" 100 0 0 100  "select timespan_reltime($1)" - ));
+DATA(insert OID = 1369 (  timestamp    PGUID 14 f t f 1 f 1296 "1296" 100 0 0 100  "select $1" - ));
+DATA(insert OID = 1370 (  timestamp    PGUID 14 f t f 1 f 1296 "1184" 100 0 0 100  "select datetime_timestamp($1)" - ));
+
+DATA(insert OID = 1380 (  date_part    PGUID 14 f t f 2 f  701 "25 1184" 100 0 0 100  "select datetime_part($1, $2)" - ));
+DATA(insert OID = 1381 (  date_part    PGUID 14 f t f 2 f  701 "25 1186" 100 0 0 100  "select timespan_part($1, $2)" - ));
+DATA(insert OID = 1382 (  date_part    PGUID 14 f t f 2 f  701 "25 702" 100 0 0 100  "select datetime_part($1, datetime($2))" - ));
+DATA(insert OID = 1383 (  date_part    PGUID 14 f t f 2 f  701 "25 703" 100 0 0 100  "select timespan_part($1, timespan($2))" - ));
+DATA(insert OID = 1384 (  date_part    PGUID 14 f t f 2 f  701 "25 1082" 100 0 0 100  "select datetime_part($1, datetime($2))" - ));
+DATA(insert OID = 1385 (  date_part    PGUID 14 f t f 2 f  701 "25 1083" 100 0 0 100  "select timespan_part($1, timespan($2))" - ));
+
+DATA(insert OID = 1390 (  isfinite     PGUID 14 f t f 1 f   16 "1184" 100 0 0 100  "select datetime_finite($1)" - ));
+DATA(insert OID = 1391 (  isfinite     PGUID 14 f t f 1 f   16 "1186" 100 0 0 100  "select timespan_finite($1)" - ));
+DATA(insert OID = 1392 (  isfinite     PGUID 14 f t f 1 f   16  "702" 100 0 0 100  "select abstime_finite($1)" - ));
+/* reserve OIDs 1370-1399 for additional date/time conversion routines! tgl 97/04/01 */
+
+DATA(insert OID = 1400 (  float        PGUID 14 f t f 1 f  701  "701" 100 0 0 100  "select $1" - ));
+DATA(insert OID = 1401 (  float        PGUID 14 f t f 1 f  701  "700" 100 0 0 100  "select ftod($1)" - ));
+DATA(insert OID = 1402 (  float4       PGUID 14 f t f 1 f  700  "700" 100 0 0 100  "select $1" - ));
+DATA(insert OID = 1403 (  float4       PGUID 14 f t f 1 f  700  "701" 100 0 0 100  "select dtof($1)" - ));
+DATA(insert OID = 1404 (  int          PGUID 14 f t f 1 f   23   "23" 100 0 0 100  "select $1" - ));
+DATA(insert OID = 1405 (  int2         PGUID 14 f t f 1 f   21   "21" 100 0 0 100  "select $1" - ));
+
+/* reserve OIDs 1370-1399 for additional date/time conversion routines! tgl 97/04/01 */
 /* Oracle Compatibility Related Functions - By Edmund Mergl <E.Mergl@bawue.de> */
-DATA(insert OID =  870 (  lower             PGUID 11 f t f 1 f 25 "25" 100 0 0 100  foo bar ));
-DATA(insert OID =  871 (  upper             PGUID 11 f t f 1 f 25 "25" 100 0 0 100  foo bar ));
-DATA(insert OID =  872 (  initcap           PGUID 11 f t f 1 f 25 "25" 100 0 0 100  foo bar ));
-DATA(insert OID =  873 (  lpad              PGUID 11 f t f 3 f 25 "25 23 25" 100 0 0 100  foo bar ));
-DATA(insert OID =  874 (  rpad              PGUID 11 f t f 3 f 25 "25 23 25" 100 0 0 100  foo bar ));
-DATA(insert OID =  875 (  ltrim             PGUID 11 f t f 2 f 25 "25 25" 100 0 0 100  foo bar ));
-DATA(insert OID =  876 (  rtrim             PGUID 11 f t f 2 f 25 "25 25" 100 0 0 100  foo bar ));
-DATA(insert OID =  877 (  substr            PGUID 11 f t f 3 f 25 "25 23 23" 100 0 0 100  foo bar ));
-DATA(insert OID =  878 (  translate         PGUID 11 f t f 3 f 25 "25 18 18" 100 0 0 100  foo bar ));
-DATA(insert OID =  879 (  lpad              PGUID 14 f t f 2 f 25 "25 23" 100 0 0 100  "select lpad($1, $2, \' \')" - ));
-DATA(insert OID =  880 (  rpad              PGUID 14 f t f 2 f 25 "25 23" 100 0 0 100  "select rpad($1, $2, \' \')" - ));
-DATA(insert OID =  881 (  ltrim             PGUID 14 f t f 1 f 25 "25" 100 0 0 100  "select ltrim($1, \' \')" - ));
-DATA(insert OID =  882 (  rtrim             PGUID 14 f t f 1 f 25 "25" 100 0 0 100  "select rtrim($1, \' \')" - ));
-DATA(insert OID =  883 (  substr            PGUID 14 f t f 2 f 25 "25 23" 100 0 0 100  "select substr($1, $2, 10000)" - ));
+DATA(insert OID =  870 (  lower        PGUID 11 f t f 1 f 25 "25" 100 0 0 100  foo bar ));
+DATA(insert OID =  871 (  upper        PGUID 11 f t f 1 f 25 "25" 100 0 0 100  foo bar ));
+DATA(insert OID =  872 (  initcap      PGUID 11 f t f 1 f 25 "25" 100 0 0 100  foo bar ));
+DATA(insert OID =  873 (  lpad         PGUID 11 f t f 3 f 25 "25 23 25" 100 0 0 100  foo bar ));
+DATA(insert OID =  874 (  rpad         PGUID 11 f t f 3 f 25 "25 23 25" 100 0 0 100  foo bar ));
+DATA(insert OID =  875 (  ltrim        PGUID 11 f t f 2 f 25 "25 25" 100 0 0 100  foo bar ));
+DATA(insert OID =  876 (  rtrim        PGUID 11 f t f 2 f 25 "25 25" 100 0 0 100  foo bar ));
+DATA(insert OID =  877 (  substr       PGUID 11 f t f 3 f 25 "25 23 23" 100 0 0 100  foo bar ));
+DATA(insert OID =  878 (  translate    PGUID 11 f t f 3 f 25 "25 18 18" 100 0 0 100  foo bar ));
+DATA(insert OID =  879 (  lpad         PGUID 14 f t f 2 f 25 "25 23" 100 0 0 100  "select lpad($1, $2, \' \')" - ));
+DATA(insert OID =  880 (  rpad         PGUID 14 f t f 2 f 25 "25 23" 100 0 0 100  "select rpad($1, $2, \' \')" - ));
+DATA(insert OID =  881 (  ltrim        PGUID 14 f t f 1 f 25 "25" 100 0 0 100  "select ltrim($1, \' \')" - ));
+DATA(insert OID =  882 (  rtrim        PGUID 14 f t f 1 f 25 "25" 100 0 0 100  "select rtrim($1, \' \')" - ));
+DATA(insert OID =  883 (  substr       PGUID 14 f t f 2 f 25 "25 23" 100 0 0 100  "select substr($1, $2, 10000)" - ));
 
 /* SEQUENCEs nextval & currval functions */
-DATA(insert OID =  1317 (  nextval          PGUID 11 f t f 1 f 23 "25" 100 0 0 100  foo bar ));
-DATA(insert OID =  1319 (  currval          PGUID 11 f t f 1 f 23 "25" 100 0 0 100  foo bar ));
+DATA(insert OID =  1317 (  nextval     PGUID 11 f t f 1 f 23 "25" 100 0 0 100  foo bar ));
+DATA(insert OID =  1319 (  currval     PGUID 11 f t f 1 f 23 "25" 100 0 0 100  foo bar ));
 #define SeqNextValueRegProcedure 1317
 #define SeqCurrValueRegProcedure 1319
 
index 680566d6a38520d25750823410a30de20759d172..7d780b7fc116a582131652bee0998dba42989b86 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.13 1997/03/25 09:25:33 scrappy Exp $
+ * $Id: builtins.h,v 1.14 1997/04/02 18:31:52 scrappy Exp $
  *
  * NOTES
  *    This should normally only be included by fmgr.h.
@@ -224,6 +224,8 @@ extern int32 reltimein(char *timestring);
 extern char *reltimeout(int32 timevalue);
 extern TimeInterval tintervalin(char *intervalstr);
 extern char *tintervalout(TimeInterval interval);
+extern RelativeTime timespan_reltime(TimeSpan *timespan);
+extern TimeSpan *reltime_timespan(RelativeTime reltime);
 extern TimeInterval mktinterval(AbsoluteTime t1, AbsoluteTime t2);
 extern AbsoluteTime timepl(AbsoluteTime t1, RelativeTime t2);
 extern AbsoluteTime timemi(AbsoluteTime t1, RelativeTime t2);
@@ -416,6 +418,7 @@ bool timestamplt(time_t t1, time_t t2);
 bool timestampgt(time_t t1, time_t t2);
 bool timestample(time_t t1, time_t t2);
 bool timestampge(time_t t1, time_t t2);
+DateTime *timestamp_datetime(time_t timestamp);
 
 /* varchar.c */
 extern char *bpcharin(char *s, int dummy, int typlen);
@@ -476,6 +479,10 @@ extern DateADT date_smaller(DateADT dateVal1, DateADT dateVal2);
 extern int32 date_mi(DateADT dateVal1, DateADT dateVal2);
 extern DateADT date_pli(DateADT dateVal, int32 days);
 extern DateADT date_mii(DateADT dateVal, int32 days);
+extern DateTime *date_datetime(DateADT date);
+extern DateADT datetime_date(DateTime *datetime);
+extern DateTime *datetime_datetime(DateADT date, TimeADT *time);
+extern DateADT abstime_date(AbsoluteTime abstime);
 
 #else
 
@@ -493,6 +500,10 @@ extern int4 date_smaller(int4 dateVal1, int4 dateVal2);
 extern int32 date_mi(int4 dateVal1, int4 dateVal2);
 extern int4 date_pli(int4 dateVal, int32 days);
 extern int4 date_mii(int4 dateVal, int32 days);
+extern DateTime *date_datetime(int4 date);
+extern int4 datetime_date(DateTime *datetime);
+extern DateTime *datetime_datetime(int4 date, TimeADT *time);
+extern int4 abstime_date(AbsoluteTime abstime);
 
 #endif
 
index e771f4cffbb0860701ae3e22df9adfa087c00385..9005f5c51fc63f7b9a61e42b2fac0b11531ea425 100644 (file)
@@ -8,7 +8,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: dt.h,v 1.4 1997/03/28 07:13:21 scrappy Exp $
+ * $Id: dt.h,v 1.5 1997/04/02 18:32:20 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,10 +36,16 @@ typedef struct {
 } TimeSpan;
 
 
-#define USE_NEW_TIME_CODE      1
+/*
+ * USE_NEW_DATE enables a more efficient Julian day-based date type.
+ * USE_NEW_TIME enables a more efficient double-based time type.
+ * These have been tested in v6.1beta, but only by myself.
+ * These should be enabled for Postgres v7.0 - tgl 97/04/02
+ */
 #define USE_NEW_DATE           0
 #define USE_NEW_TIME           0
 
+
 /* ----------------------------------------------------------------
  *             time types + support macros
  *
@@ -225,12 +231,13 @@ typedef struct {
                                || DATETIME_IS_NOBEGIN(j) || DATETIME_IS_NOEND(j))
 #define DATETIME_IS_RESERVED(j) (DATETIME_IS_RELATIVE(j) || DATETIME_NOT_FINITE(j))
 
-#define TIMESPAN_INVALID(j)    {j->time = DT_INVALID;}
+#define TIMESPAN_INVALID(j)    {(j).time = DT_INVALID;}
 #ifdef NAN
 #define TIMESPAN_IS_INVALID(j) (isnan((j).time))
 #else
 #define TIMESPAN_IS_INVALID(j) ((j).time == DT_INVALID)
 #endif
+#define TIMESPAN_NOT_FINITE(j) TIMESPAN_IS_INVALID(j)
 
 #define TIME_PREC 1e-6
 #define JROUND(j) (rint(((double) j)/TIME_PREC)*TIME_PREC)
@@ -247,6 +254,7 @@ extern bool datetime_lt(DateTime *dt1, DateTime *dt2);
 extern bool datetime_le(DateTime *dt1, DateTime *dt2);
 extern bool datetime_ge(DateTime *dt1, DateTime *dt2);
 extern bool datetime_gt(DateTime *dt1, DateTime *dt2);
+extern bool datetime_finite(DateTime *datetime);
 
 extern TimeSpan *timespan_in(char *str);
 extern char *timespan_out(TimeSpan *span);
@@ -256,9 +264,14 @@ extern bool timespan_lt(TimeSpan *span1, TimeSpan *span2);
 extern bool timespan_le(TimeSpan *span1, TimeSpan *span2);
 extern bool timespan_ge(TimeSpan *span1, TimeSpan *span2);
 extern bool timespan_gt(TimeSpan *span1, TimeSpan *span2);
+extern bool timespan_finite(TimeSpan *span);
 
-float64 datetime_part(text *units, DateTime *datetime);
-float64 timespan_part(text *units, TimeSpan *timespan);
+extern text *datetime_text(DateTime *datetime);
+extern DateTime *text_datetime(text *str);
+extern text *timespan_text(TimeSpan *timespan);
+extern TimeSpan *text_timespan(text *str);
+extern float64 datetime_part(text *units, DateTime *datetime);
+extern float64 timespan_part(text *units, TimeSpan *timespan);
 
 extern TimeSpan *timespan_um(TimeSpan *span);
 extern TimeSpan *timespan_add(TimeSpan *span1, TimeSpan *span2);
@@ -269,12 +282,12 @@ extern DateTime *datetime_add_span(DateTime *dt, TimeSpan *span);
 extern DateTime *datetime_sub_span(DateTime *dt, TimeSpan *span);
 
 extern void GetCurrentTime(struct tm *tm);
-DateTime SetDateTime(DateTime datetime);
-DateTime tm2datetime(struct tm *tm, double fsec, int tzp);
-int datetime2tm( DateTime dt, struct tm *tm, double *fsec);
+extern DateTime SetDateTime(DateTime datetime);
+extern DateTime tm2datetime(struct tm *tm, double fsec, int *tzp);
+extern int datetime2tm( DateTime dt, int *tzp, struct tm *tm, double *fsec);
 
-int timespan2tm(TimeSpan span, struct tm *tm, float8 *fsec);
-int tm2timespan(struct tm *tm, double fsec, TimeSpan *span);
+extern int timespan2tm(TimeSpan span, struct tm *tm, float8 *fsec);
+extern int tm2timespan(struct tm *tm, double fsec, TimeSpan *span);
 
 extern DateTime dt2local( DateTime dt, int timezone);
 
index e8691f72731fc214078c1d46dee8b1340c2a8b0a..400bb045c5c4b2c7505065980f638518e38a20ee 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nabstime.h,v 1.6 1997/03/25 08:11:24 scrappy Exp $
+ * $Id: nabstime.h,v 1.7 1997/04/02 18:32:39 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -84,17 +84,8 @@ typedef TimeIntervalData *TimeInterval;
 #define RelativeTimeIsValid(time) \
     ((bool) (((RelativeTime) time) != INVALID_RELTIME))
 
-#if USE_NEW_TIME_CODE
-
 extern AbsoluteTime GetCurrentAbsoluteTime(void);
 
-#else
-
-#define GetCurrentAbsoluteTime() \
-    ((AbsoluteTime) getSystemTime())
-
-#endif
-
 /*
  * getSystemTime --
  *     Returns system time.
@@ -121,11 +112,17 @@ extern bool abstimelt(AbsoluteTime t1, AbsoluteTime t2);
 extern bool abstimegt(AbsoluteTime t1, AbsoluteTime t2);
 extern bool abstimele(AbsoluteTime t1, AbsoluteTime t2);
 extern bool abstimege(AbsoluteTime t1, AbsoluteTime t2);
+extern bool abstime_finite(AbsoluteTime time);
 
 extern AbsoluteTime datetime_abstime(DateTime *datetime);
+extern DateTime *abstime_datetime(AbsoluteTime abstime);
 
 extern bool AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2);
 extern bool AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2);
+
+extern AbsoluteTime tm2abstime(struct tm *tm, int tz);
+extern void abstime2tm(AbsoluteTime time, int *tzp, struct tm *tm);
+
 extern AbsoluteTime dateconv(struct tm *tm, int zone);
 extern time_t qmktime(struct tm *tp);
 
index 3a667260b8ecf2f399ede6c86daeb32edec36745..5f2cf8d45631c8e215ce1f00b8beab149c2c1586 100644 (file)
@@ -1,17 +1,15 @@
 .\" This is -*-nroff-*-
 .\" XXX standard disclaimer belongs here....
-.\" $Header: /cvsroot/pgsql/src/man/Attic/built-in.3,v 1.3 1996/12/11 00:27:02 momjian Exp $
-.TH BUILT-INS INTRO 11/05/95 PostgreSQL PostgreSQL
+.\" $Header: /cvsroot/pgsql/src/man/Attic/built-in.3,v 1.4 1997/04/02 18:31:22 scrappy Exp $
+.TH BUILT-INS INTRO 04/01/97 PostgreSQL PostgreSQL
 .SH "DESCRIPTION"
 This section describes the data types, functions and operators
 available to users in Postgres as it is distributed.
-.SH "Built-in and System Types"
 .SH "BUILT-IN TYPES"
-This section describes both 
+This section describes 
 .BR built-in
 data types.
-These Built-in types are 
-are installed in every database.
+These Built-in types are installed in every database.
 .PP
 Users may add new types to Postgres using the
 .IR "define type"
@@ -24,9 +22,9 @@ described in this section.
 .in 0
 .nf
        \fBPOSTGRES Type\fP     \fBMeaning\fP
-       abstime absolute date and time
+       abstime (absolute) limited-range date and time
        aclitem access control list item
-       bool    boolean 
+       bool    boolean
        box     2-dimensional rectangle
        bpchar  blank-padded characters
        bytea   variable length array of bytes
@@ -37,11 +35,12 @@ described in this section.
        char16  array of 16 characters
        cid     command identifier type
        date    ANSI SQL date type
+       datetime        general-use date and time
        filename        large object filename
        int     alias for int4
        integer alias for int4
        int2    two-byte signed integer
-       int28   array of 8 int2 
+       int28   array of 8 int2
        int4    four-byte signed integer
        float   alias for float4
        float4  single-precision floating-point number
@@ -50,7 +49,7 @@ described in this section.
        name    a multi-character type for storing system identifiers
        oid     object identifier type
        oid8    array of 8 oid
-       oidchar16       oid and char16 composed 
+       oidchar16       oid and char16 composed
        oidint2 oid and int2 composed
        oidint4 oid and int4 composed
        path    variable-length array of lseg
@@ -58,13 +57,15 @@ described in this section.
        polygon 2-dimensional polygon
        real    alias for float4
        regproc registered procedure
-       reltime relative date and time
-       smgr    storage manager 
+       reltime (relative) date and time span (duration)
+       smgr    storage manager
        smallint        alias for int2
        text    variable length array of characters
        tid     tuple identifier type
-       time    ANSI SQL time type 
-       tinterval       time interval
+       time    ANSI SQL time type
+       timespan        general-use time span (duration)
+       timestamp       limited-range ISO-format date and time
+       tinterval       time interval (start and stop abstime)
        varchar variable-length characters
        xid     transaction identifier type
 
@@ -73,11 +74,94 @@ described in this section.
 .PP
 As a rule, the built-in types are all either (1) internal types, in
 which case the user should not worry about their external format, or
-(2) have obvious formats.  The exceptions to this rule are the three
+(2) have obvious formats.  The exceptions to this rule are the date and
 time types.
+
 .SH "Syntax of date and time types"
+.SH "DATETIME"
+General-use date and time is input using a wide range of
+syntaxes, including ISO-compatible, SQL-compatible, traditional
+Postgres (see section on
+.IR "absolute time")
+and other permutations of date and time. Output styles can be ISO-compatible,
+SQL-compatible, or traditional Postgres, with the default set to be compatible
+with Postgres v6.0.
+.PP
+datetime is specified using the following syntax:
+.PP
+.nf
+Year-Month-Day [ Hour : Minute : Second ]      [AD,BC] [ Timezone ]
+.nf
+  YearMonthDay [ Hour : Minute : Second ]      [AD,BC] [ Timezone ]
+.nf
+     Month Day [ Hour : Minute : Second ] Year [AD,BC] [ Timezone ]
+.sp
+where  
+       Year is 4013 BC, ..., very large
+       Month is Jan, Feb, ..., Dec or 1, 2, ..., 12
+       Day is 1, 2, ..., 31
+       Hour is 00, 02, ..., 23
+       Minute is 00, 01, ..., 59
+       Second is 00, 01, ..., 59 (60 for leap second)
+       Timezone is 3 characters or ISO offset to GMT
+.fi
+.PP
+Valid dates are from Nov 13 00:00:00 4013 BC GMT to far into the future.
+Timezones are either three characters (e.g. "GMT" or "PST") or ISO-compatible
+offsets to GMT (e.g. "-08" or "-08:00" when in Pacific Standard Time).
+Dates are stored internally in Greenwich Mean Time. Input and output routines 
+translate time to the local time zone of the server.
+.PP
+All special values allowed for
+.IR "absolute time"
+are also allowed for
+.IR "datetime".
+The special values \*(lqcurrent\*(rq,
+\*(lqinfinity\*(rq and \*(lq-infinity\*(rq are provided.
+\*(lqinfinity\*(rq specifies a time later than any valid time, and
+\*(lq-infinity\*(rq specifies a time earlier than any valid time.
+\*(lqcurrent\*(rq indicates that the current time should be
+substituted whenever this value appears in a computation.
+.PP
+The strings \*(lqnow\*(rq and \*(lqepoch\*(rq can be used to specify
+time values.  \*(lqnow\*(rq means the current time, and differs from
+\*(lqcurrent\*(rq in that the current time is immediately substituted
+for it.  \*(lqepoch\*(rq means Jan 1 00:00:00 1970 GMT.
+
+
+.SH "TIMESPAN"
+General-use time span is input using a wide range of
+syntaxes, including ISO-compatible, SQL-compatible, traditional
+Postgres (see section on
+.IR "relative time"
+) and other permutations of time span. Output formats can be ISO-compatible,
+SQL-compatible, or traditional Postgres, with the default set to be Postgres-compatible.
+Months and years are a "qualitative" time interval, and are stored separately
+from the other "quantitative" time intervals such as day or hour. For date arithmetic,
+the qualitative time units are instantiated in the context of the relevant date or time.
+.PP
+Time span is specified with the following syntax:
+.PP
+.nf
+  Quantity Unit [Quantity Unit...] [Direction]
+.nf
+@ Quantity Unit [Direction]
+.sp
+where  
+       Quantity is ..., '-1', '0', `1', `2', ...
+       Unit is `second', `minute', `hour', `day', `week', `month', `year',
+       or abbreviations or plurals of these units.
+       Direction is ``ago''
+.fi
 .SH "ABSOLUTE TIME"
+Absolute time (abstime) is a limited-range (+/- 68 years) and limited-precision (1 sec)
+date data type.
+.IR "datetime"
+may be preferred, since it
+covers a larger range with greater precision.
+.PP
 Absolute time is specified using the following syntax:
+.PP
 .nf
 Month  Day [ Hour : Minute : Second ]  Year [ Timezone ]
 .sp
@@ -89,6 +173,7 @@ where
        Second is 00, 01, ..., 59
        Year is 1901, 1902, ..., 2038
 .fi
+.PP
 Valid dates are from Dec 13 20:45:53 1901 GMT to Jan 19 03:14:04
 2038 GMT.  As of Version 3.0, times are no longer read and written
 using Greenwich Mean Time; the input and output routines default to
@@ -105,8 +190,19 @@ The strings \*(lqnow\*(rq and \*(lqepoch\*(rq can be used to specify
 time values.  \*(lqnow\*(rq means the current time, and differs from
 \*(lqcurrent\*(rq in that the current time is immediately substituted
 for it.  \*(lqepoch\*(rq means Jan 1 00:00:00 1970 GMT.
+
 .SH "RELATIVE TIME"
+Relative time (reltime) is a limited-range (+/- 68 years) and limited-precision (1 sec)
+time span data type.
+.IR "timespan"
+may be preferred, since it
+covers a larger range with greater precision, allows multiple units
+for an entry, and correctly handles qualitative time
+units such as year and month. For reltime, only one quantity and unit is allowed
+per entry, which can be inconvenient for complicated time spans.
+.PP
 Relative time is specified with the following syntax:
+.PP
 .nf
 @ Quantity Unit [Direction]
 .sp
@@ -124,6 +220,7 @@ In addition, the special relative time \*(lqUndefined RelTime\*(rq is
 provided.
 .SH "TIME RANGES"
 Time ranges are specified as:
+.PP
 .nf
 [ 'abstime' 'abstime']
 .fi
@@ -131,6 +228,7 @@ where
 .IR abstime
 is a time in the absolute time format.  Special abstime values such as 
 \*(lqcurrent\*(rq, \*(lqinfinity\*(rq and \*(lq-infinity\*(rq can be used.
+
 .SH "Built-in operators and functions"
 .SH OPERATORS
 Postgres provides a large number of built-in operators on system types.
@@ -151,31 +249,8 @@ select * from emp where int4lt(salary, 40000);
 The rest of this section provides a list of the built-in operators and
 the functions that implement them.  Binary operators are listed first,
 followed by unary operators.
-.SH "BINARY OPERATORS"
-This list was generated from the Postgres system catalogs with the
-query:
 
-.nf
-SELECT
-       t0.typname AS result,
-        t1.typname AS left_type,
-        t2.typname AS right_type,
-        o.oprname AS operatr,
-        p.proname AS func_name
-FROM   pg_proc p, pg_type t0,
-        pg_type t1, pg_type t2,
-        pg_operator o
-WHERE  p.prorettype = t0.oid AND
-        RegprocToOid(o.oprcode) = p.oid AND
-       p.pronargs = 2 AND
-       o.oprleft = t1.oid AND
-       o.oprright = t2.oid
-ORDER BY result, left_type, right_type, operatr;
-.fi
-
-These operations are cast in terms of SQL types and so are
-.BR not
-directly usable as C function prototypes.
+.SH "BINARY OPERATORS"
 
 .nf
 Operators:
@@ -262,6 +337,68 @@ tinterval
        <?>     abstime in tinterval
        |       start of interval
        <#>     convert to interval
+.fi
+
+.SH "FUNCTIONS"
+Many data types have functions available for conversion to other related types.
+In addition, there are some type-specific functions.
+
+.nf
+Functions:
+
+abstime
+       datetime datetime(abstime)        convert to datetime
+       bool     isfinite(abstime)        TRUE if this is a finite time
+
+date
+       datetime datetime(date)           convert to datetime
+       datetime datetime(date,time)      convert to datetime
+
+datetime
+       abstime  abstime(datetime)        convert to abstime
+       float8   date_part(text,datetime) specified portion of date field
+       bool     isfinite(datetime)       TRUE if this is a finite time
+
+reltime
+       timespan timespan(reltime)        convert to timespan
+
+time
+       datetime datetime(date,time)      convert to datetime
+
+timespan
+       float8   date_part(text,timespan) specified portion of time field
+       bool     isfinite(timespan)       TRUE if this is a finite time
+       reltime  reltime(timespan)        convert to reltime
+.fi
+
+.PP
+This list was generated from the Postgres system catalogs with the
+query:
+
+.nf
+SELECT
+       t0.typname AS result,
+       t1.typname AS left_type,
+       t2.typname AS right_type,
+       o.oprname AS operatr,
+       p.proname AS func_name
+FROM
+       pg_proc p, pg_type t0,
+       pg_type t1, pg_type t2,
+       pg_operator o
+WHERE
+       p.prorettype = t0.oid AND
+       RegprocToOid(o.oprcode) = p.oid AND
+       p.pronargs = 2 AND
+       o.oprleft = t1.oid AND
+       o.oprright = t2.oid
+ORDER BY
+       result, left_type, right_type, operatr;
+.fi
+
+These operations are cast in terms of SQL types and so are
+.BR not
+directly usable as C function prototypes.
 
 result   |left_type |right_type|operatr|func_name      
 ---------+----------+----------+-------+---------------