aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorThomas G. Lockhart <lockhart@fourpalms.org>2001-09-28 08:09:14 +0000
committerThomas G. Lockhart <lockhart@fourpalms.org>2001-09-28 08:09:14 +0000
commit6f58115dddfa8ca63004c4784f57ef660422861d (patch)
tree71816e03286e53113ec4b6de337f0b345028a314 /src/backend
parent1f075a32ee28004251f508f50a4325944801da10 (diff)
downloadpostgresql-6f58115dddfa8ca63004c4784f57ef660422861d.tar.gz
postgresql-6f58115dddfa8ca63004c4784f57ef660422861d.zip
Measure the current transaction time to milliseconds.
Define a new function, GetCurrentTransactionStartTimeUsec() to get the time to this precision. Allow now() and timestamp 'now' to use this higher precision result so we now have fractional seconds in this "constant". Add timestamp without time zone type. Move previous timestamp type to timestamp with time zone. Accept another ISO variant for date/time values: yyyy-mm-ddThh:mm:ss (note the "T" separating the day from hours information). Remove 'current' from date/time types; convert to 'now' in input. Separate time and timetz regression tests. Separate timestamp and timestamptz regression test.
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/transam/xact.c20
-rw-r--r--src/backend/parser/gram.y24
-rw-r--r--src/backend/parser/parse_coerce.c18
-rw-r--r--src/backend/parser/parse_expr.c6
-rw-r--r--src/backend/parser/parse_target.c17
-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
11 files changed, 1735 insertions, 991 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index c3d6326d42a..6b0d4de720e 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.109 2001/08/25 18:52:41 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.110 2001/09/28 08:08:57 thomas Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
@@ -370,6 +370,21 @@ GetCurrentTransactionStartTime(void)
/* --------------------------------
+ * GetCurrentTransactionStartTimeUsec
+ * --------------------------------
+ */
+AbsoluteTime
+GetCurrentTransactionStartTimeUsec(int *msec)
+{
+ TransactionState s = CurrentTransactionState;
+
+ *msec = s->startTimeMsec;
+
+ return s->startTime;
+}
+
+
+/* --------------------------------
* TransactionIdIsCurrentTransactionId
* --------------------------------
*/
@@ -859,7 +874,10 @@ StartTransaction(void)
*/
s->commandId = FirstCommandId;
s->scanCommandId = FirstCommandId;
+#if NOT_USED
s->startTime = GetCurrentAbsoluteTime();
+#endif
+ s->startTime = GetCurrentAbsoluteTimeUsec(&(s->startTimeMsec));
/*
* initialize the various transaction subsystems
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 64d71d28bd7..0298742c611 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.253 2001/09/23 03:39:01 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.254 2001/09/28 08:09:09 thomas Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -259,7 +259,7 @@ static void doNegateFloat(Value *v);
%type <str> opt_charset, opt_collate
%type <str> opt_float
%type <ival> opt_numeric, opt_decimal
-%type <boolean> opt_varying, opt_timezone
+%type <boolean> opt_varying, opt_timezone, opt_timezone_x
%type <ival> Iconst
%type <str> Sconst, comment_text
@@ -4229,10 +4229,16 @@ ConstDatetime: datetime
$$->name = xlateSqlType($1);
$$->typmod = -1;
}
- | TIMESTAMP opt_timezone
+ | TIMESTAMP opt_timezone_x
{
$$ = makeNode(TypeName);
- $$->name = xlateSqlType("timestamp");
+ if ($2)
+ $$->name = xlateSqlType("timestamptz");
+ else
+ $$->name = xlateSqlType("timestamp");
+ /* XXX the timezone field seems to be unused
+ * - thomas 2001-09-06
+ */
$$->timezone = $2;
$$->typmod = -1;
}
@@ -4263,6 +4269,16 @@ datetime: YEAR_P { $$ = "year"; }
| SECOND_P { $$ = "second"; }
;
+/* XXX Make the default be WITH TIME ZONE for 7.2 to help with database upgrades
+ * but revert this back to WITHOUT TIME ZONE for 7.3.
+ * Do this by simply reverting opt_timezone_x to opt_timezone - thomas 2001-09-06
+ */
+
+opt_timezone_x: WITH TIME ZONE { $$ = TRUE; }
+ | WITHOUT TIME ZONE { $$ = FALSE; }
+ | /*EMPTY*/ { $$ = TRUE; }
+ ;
+
opt_timezone: WITH TIME ZONE { $$ = TRUE; }
| WITHOUT TIME ZONE { $$ = FALSE; }
| /*EMPTY*/ { $$ = FALSE; }
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 5f769a81eac..80164f86b3a 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.60 2001/06/24 02:41:21 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.61 2001/09/28 08:09:09 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -240,7 +240,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
oid_array[0] = inputTypeId;
ftup = SearchSysCache(PROCNAME,
- PointerGetDatum(typeidTypeName(targetTypeId)),
+ PointerGetDatum(typeidTypeName(targetTypeId)),
Int32GetDatum(1),
PointerGetDatum(oid_array),
0);
@@ -498,6 +498,7 @@ TypeCategory(Oid inType)
case (TIMETZOID):
case (ABSTIMEOID):
case (TIMESTAMPOID):
+ case (TIMESTAMPTZOID):
result = DATETIME_TYPE;
break;
@@ -577,7 +578,10 @@ PreferredType(CATEGORY category, Oid type)
break;
case (DATETIME_TYPE):
- result = TIMESTAMPOID;
+ if (type == DATEOID)
+ result = TIMESTAMPOID;
+ else
+ result = TIMESTAMPTZOID;
break;
case (TIMESPAN_TYPE):
@@ -634,10 +638,14 @@ PromoteTypeToNext(Oid inType)
break;
case (DATEOID):
- case (ABSTIMEOID):
result = TIMESTAMPOID;
break;
+ case (ABSTIMEOID):
+ case (TIMESTAMPOID):
+ result = TIMESTAMPTZOID;
+ break;
+
case (TIMEOID):
case (RELTIMEOID):
result = INTERVALOID;
@@ -646,7 +654,7 @@ PromoteTypeToNext(Oid inType)
case (BOOLOID):
case (TEXTOID):
case (FLOAT8OID):
- case (TIMESTAMPOID):
+ case (TIMESTAMPTZOID):
case (INTERVALOID):
default:
result = inType;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index e1574993529..d1512c61c0e 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.101 2001/09/20 23:31:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.102 2001/09/28 08:09:09 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,11 +40,11 @@ bool Transform_null_equals = false;
static Node *parser_typecast_constant(Value *expr, TypeName *typename);
static Node *parser_typecast_expression(ParseState *pstate,
- Node *expr, TypeName *typename);
+ Node *expr, TypeName *typename);
static Node *transformAttr(ParseState *pstate, Attr *att, int precedence);
static Node *transformIdent(ParseState *pstate, Ident *ident, int precedence);
static Node *transformIndirection(ParseState *pstate, Node *basenode,
- List *indirection);
+ List *indirection);
/*
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index a39e3108804..c40792072b1 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.72 2001/09/17 01:06:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.73 2001/09/28 08:09:09 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -462,10 +462,13 @@ FigureColname(Node *node)
{
if (node == NULL)
return "?column?";
+
switch (nodeTag(node))
{
case T_Ident:
return ((Ident *) node)->name;
+ case T_A_Const:
+ return (FigureColname((Node *)((A_Const *) node)->typename));
case T_Attr:
{
List *attrs = ((Attr *) node)->attrs;
@@ -481,7 +484,15 @@ FigureColname(Node *node)
case T_FuncCall:
return ((FuncCall *) node)->funcname;
case T_TypeCast:
- return FigureColname(((TypeCast *) node)->arg);
+ {
+ char *name;
+
+ name = FigureColname(((TypeCast *) node)->arg);
+ if (strcmp(name, "?column?") == 0)
+ name = FigureColname((Node *)((TypeCast *) node)->typename);
+ return name;
+ }
+ break;
case T_CaseExpr:
{
char *name;
@@ -492,6 +503,8 @@ FigureColname(Node *node)
return name;
}
break;
+ case T_TypeName:
+ return ((TypeName *) node)->name;
default:
break;
}
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() */