Skip to content
Snippets Groups Projects
date.c 54.8 KiB
Newer Older
/*-------------------------------------------------------------------------
 *
 *	  implements DATE and TIME data types specified in SQL-92 standard
PostgreSQL Daemon's avatar
 
PostgreSQL Daemon committed
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994-5, Regents of the University of California
 *	  $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.123 2006/02/09 03:39:17 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"
#include <time.h>
Bruce Momjian's avatar
Bruce Momjian committed
#include "miscadmin.h"
#include "utils/builtins.h"
Bruce Momjian's avatar
Bruce Momjian committed
#include "utils/date.h"
#include "utils/nabstime.h"
#include "utils/timestamp.h"
/*
 * gcc's -ffast-math switch breaks routines that expect exact results from
 * expressions like timeval / SECS_PER_HOUR, where timeval is double.
 */
#ifdef __FAST_MATH__
#error -ffast-math is known to break this code
#endif

static int	time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec);
static int	timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp);
static int	tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result);
static int	tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result);
static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
/*****************************************************************************
 *****************************************************************************/


/* date_in()
 * Given date text string, convert to internal date format.
Datum
date_in(PG_FUNCTION_ARGS)
	char	   *str = PG_GETARG_CSTRING(0);
	DateADT		date;
Bruce Momjian's avatar
Bruce Momjian committed
	struct pg_tm tt,
	dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
						  field, ftype, MAXDATEFIELDS, &nf);
	if (dterr == 0)
		dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
	if (dterr != 0)
		DateTimeParseError(dterr, str, "date");
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
			  errmsg("date/time value \"current\" is no longer supported")));
Jan Wieck's avatar
Jan Wieck committed
			GetCurrentDateTime(tm);
			DateTimeParseError(DTERR_BAD_FORMAT, str, "date");
			break;
	if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
		ereport(ERROR,
				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
				 errmsg("date out of range: \"%s\"", str)));

	date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
/* date_out()
 * Given internal format date, convert to text string.
Datum
date_out(PG_FUNCTION_ARGS)
	DateADT		date = PG_GETARG_DATEADT(0);
Bruce Momjian's avatar
Bruce Momjian committed
	struct pg_tm tt,
	j2date(date + POSTGRES_EPOCH_JDATE,
		   &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
	EncodeDateOnly(tm, DateStyle, buf);
	result = pstrdup(buf);
	PG_RETURN_CSTRING(result);
}
/*
 *		date_recv			- converts external binary format to date
 */
Datum
date_recv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);

	PG_RETURN_DATEADT((DateADT) pq_getmsgint(buf, sizeof(DateADT)));
}

/*
 *		date_send			- converts date to binary format
 */
Datum
date_send(PG_FUNCTION_ARGS)
{
	DateADT		date = PG_GETARG_DATEADT(0);
	StringInfoData buf;

	pq_begintypsend(&buf);
	pq_sendint(&buf, date, sizeof(date));
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}


Datum
date_eq(PG_FUNCTION_ARGS)
{
	DateADT		dateVal1 = PG_GETARG_DATEADT(0);
	DateADT		dateVal2 = PG_GETARG_DATEADT(1);
	PG_RETURN_BOOL(dateVal1 == dateVal2);
}
	DateADT		dateVal1 = PG_GETARG_DATEADT(0);
	DateADT		dateVal2 = PG_GETARG_DATEADT(1);

	PG_RETURN_BOOL(dateVal1 != dateVal2);
	DateADT		dateVal1 = PG_GETARG_DATEADT(0);
	DateADT		dateVal2 = PG_GETARG_DATEADT(1);

	PG_RETURN_BOOL(dateVal1 < dateVal2);
	DateADT		dateVal1 = PG_GETARG_DATEADT(0);
	DateADT		dateVal2 = PG_GETARG_DATEADT(1);
	PG_RETURN_BOOL(dateVal1 <= dateVal2);
}
	DateADT		dateVal1 = PG_GETARG_DATEADT(0);
	DateADT		dateVal2 = PG_GETARG_DATEADT(1);

	PG_RETURN_BOOL(dateVal1 > dateVal2);
}
	DateADT		dateVal1 = PG_GETARG_DATEADT(0);
	DateADT		dateVal2 = PG_GETARG_DATEADT(1);

	PG_RETURN_BOOL(dateVal1 >= dateVal2);
}
Datum
date_cmp(PG_FUNCTION_ARGS)
	DateADT		dateVal1 = PG_GETARG_DATEADT(0);
	DateADT		dateVal2 = PG_GETARG_DATEADT(1);

	else if (dateVal1 > dateVal2)
		PG_RETURN_INT32(1);
	PG_RETURN_INT32(0);
}
Datum
date_larger(PG_FUNCTION_ARGS)
	DateADT		dateVal1 = PG_GETARG_DATEADT(0);
	DateADT		dateVal2 = PG_GETARG_DATEADT(1);
	PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
}

Datum
date_smaller(PG_FUNCTION_ARGS)
	DateADT		dateVal1 = PG_GETARG_DATEADT(0);
	DateADT		dateVal2 = PG_GETARG_DATEADT(1);

	PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
}
/* Compute difference between two dates in days.
	DateADT		dateVal1 = PG_GETARG_DATEADT(0);
	DateADT		dateVal2 = PG_GETARG_DATEADT(1);

	PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
}
/* Add a number of days to a date, giving a new date.
 * Must handle both positive and negative numbers of days.
Datum
date_pli(PG_FUNCTION_ARGS)
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	int32		days = PG_GETARG_INT32(1);

	PG_RETURN_DATEADT(dateVal + days);
}
/* Subtract a number of days from a date, giving a new date.
Datum
date_mii(PG_FUNCTION_ARGS)
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	int32		days = PG_GETARG_INT32(1);
	PG_RETURN_DATEADT(dateVal - days);
}
/*
 * Internal routines for promoting date to timestamp and timestamp with
 * time zone
#ifdef HAVE_INT64_TIMESTAMP
/* date is days since 2000, timestamp is microseconds since same... */
#define date2timestamp(dateVal) \
	((Timestamp) ((dateVal) * USECS_PER_DAY))
#else
/* date is days since 2000, timestamp is seconds since same... */
#define date2timestamp(dateVal) \
	((Timestamp) ((dateVal) * (double)SECS_PER_DAY))
#endif

static TimestampTz
date2timestamptz(DateADT dateVal)
{
	TimestampTz result;
Bruce Momjian's avatar
Bruce Momjian committed
	struct pg_tm tt,

	j2date(dateVal + POSTGRES_EPOCH_JDATE,
		   &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));

	tm->tm_hour = 0;
	tm->tm_min = 0;
	tm->tm_sec = 0;
	tz = DetermineTimeZoneOffset(tm, global_timezone);
	result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
	result = dateVal * (double) SECS_PER_DAY + tz;
#endif

	return result;
}


/*
 * Crosstype comparison functions for dates
 */

Datum
date_eq_timestamp(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	Timestamp	dt2 = PG_GETARG_TIMESTAMP(1);
	Timestamp	dt1;

	dt1 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
}

Datum
date_ne_timestamp(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	Timestamp	dt2 = PG_GETARG_TIMESTAMP(1);
	Timestamp	dt1;

	dt1 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
}

Datum
date_lt_timestamp(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	Timestamp	dt2 = PG_GETARG_TIMESTAMP(1);
	Timestamp	dt1;

	dt1 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
}

Datum
date_gt_timestamp(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	Timestamp	dt2 = PG_GETARG_TIMESTAMP(1);
	Timestamp	dt1;

	dt1 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
}

Datum
date_le_timestamp(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	Timestamp	dt2 = PG_GETARG_TIMESTAMP(1);
	Timestamp	dt1;

	dt1 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
}

Datum
date_ge_timestamp(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	Timestamp	dt2 = PG_GETARG_TIMESTAMP(1);
	Timestamp	dt1;

	dt1 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
}

Datum
date_cmp_timestamp(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	Timestamp	dt2 = PG_GETARG_TIMESTAMP(1);
	Timestamp	dt1;

	dt1 = date2timestamp(dateVal);

	PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
}

Datum
date_eq_timestamptz(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
	TimestampTz dt1;

	dt1 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
}

Datum
date_ne_timestamptz(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
	TimestampTz dt1;

	dt1 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
}

Datum
date_lt_timestamptz(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
	TimestampTz dt1;

	dt1 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
}

Datum
date_gt_timestamptz(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
	TimestampTz dt1;

	dt1 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
}

Datum
date_le_timestamptz(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
	TimestampTz dt1;

	dt1 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
}

Datum
date_ge_timestamptz(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
	TimestampTz dt1;

	dt1 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
}

Datum
date_cmp_timestamptz(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
	TimestampTz dt1;

	dt1 = date2timestamptz(dateVal);

	PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
}

Datum
timestamp_eq_date(PG_FUNCTION_ARGS)
{
	Timestamp	dt1 = PG_GETARG_TIMESTAMP(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
	Timestamp	dt2;

	dt2 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
}

Datum
timestamp_ne_date(PG_FUNCTION_ARGS)
{
	Timestamp	dt1 = PG_GETARG_TIMESTAMP(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
	Timestamp	dt2;

	dt2 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
}

Datum
timestamp_lt_date(PG_FUNCTION_ARGS)
{
	Timestamp	dt1 = PG_GETARG_TIMESTAMP(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
	Timestamp	dt2;

	dt2 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
}

Datum
timestamp_gt_date(PG_FUNCTION_ARGS)
{
	Timestamp	dt1 = PG_GETARG_TIMESTAMP(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
	Timestamp	dt2;

	dt2 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
}

Datum
timestamp_le_date(PG_FUNCTION_ARGS)
{
	Timestamp	dt1 = PG_GETARG_TIMESTAMP(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
	Timestamp	dt2;

	dt2 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
}

Datum
timestamp_ge_date(PG_FUNCTION_ARGS)
{
	Timestamp	dt1 = PG_GETARG_TIMESTAMP(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
	Timestamp	dt2;

	dt2 = date2timestamp(dateVal);

	PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
}

Datum
timestamp_cmp_date(PG_FUNCTION_ARGS)
{
	Timestamp	dt1 = PG_GETARG_TIMESTAMP(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
	Timestamp	dt2;

	dt2 = date2timestamp(dateVal);

	PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
}

Datum
timestamptz_eq_date(PG_FUNCTION_ARGS)
{
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2;

	dt2 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
}

Datum
timestamptz_ne_date(PG_FUNCTION_ARGS)
{
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2;

	dt2 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
}

Datum
timestamptz_lt_date(PG_FUNCTION_ARGS)
{
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2;

	dt2 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
}

Datum
timestamptz_gt_date(PG_FUNCTION_ARGS)
{
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2;

	dt2 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
}

Datum
timestamptz_le_date(PG_FUNCTION_ARGS)
{
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2;

	dt2 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
}

Datum
timestamptz_ge_date(PG_FUNCTION_ARGS)
{
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2;

	dt2 = date2timestamptz(dateVal);

	PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
}

Datum
timestamptz_cmp_date(PG_FUNCTION_ARGS)
{
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
	DateADT		dateVal = PG_GETARG_DATEADT(1);
Bruce Momjian's avatar
Bruce Momjian committed
	TimestampTz dt2;

	dt2 = date2timestamptz(dateVal);

	PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
}


/* Add an interval to a date, giving a new date.
 * Must handle both positive and negative intervals.
 *
 * We implement this by promoting the date to timestamp (without time zone)
 * and then using the timestamp plus interval function.
 */
Datum
date_pl_interval(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	Interval   *span = PG_GETARG_INTERVAL_P(1);
	dateStamp = date2timestamp(dateVal);
	return DirectFunctionCall2(timestamp_pl_interval,
							   TimestampGetDatum(dateStamp),
							   PointerGetDatum(span));
}

/* Subtract an interval from a date, giving a new date.
 * Must handle both positive and negative intervals.
 *
 * We implement this by promoting the date to timestamp (without time zone)
 * and then using the timestamp minus interval function.
 */
Datum
date_mi_interval(PG_FUNCTION_ARGS)
{
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	Interval   *span = PG_GETARG_INTERVAL_P(1);
	dateStamp = date2timestamp(dateVal);
	return DirectFunctionCall2(timestamp_mi_interval,
							   TimestampGetDatum(dateStamp),
							   PointerGetDatum(span));
/* date_timestamp()
 * Convert date to timestamp data type.
Datum
date_timestamp(PG_FUNCTION_ARGS)
	DateADT		dateVal = PG_GETARG_DATEADT(0);
	Timestamp	result;
	result = date2timestamp(dateVal);

	PG_RETURN_TIMESTAMP(result);
}


/* timestamp_date()
 * Convert timestamp to date data type.
 */
Datum
timestamp_date(PG_FUNCTION_ARGS)
{
	Timestamp	timestamp = PG_GETARG_TIMESTAMP(0);
Bruce Momjian's avatar
Bruce Momjian committed
	struct pg_tm tt,

	if (TIMESTAMP_NOT_FINITE(timestamp))
		PG_RETURN_NULL();

	if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
		ereport(ERROR,
				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
				 errmsg("timestamp out of range")));

	result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;

	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);
	result = date2timestamptz(dateVal);
/* timestamptz_date()
 * Convert timestamp with time zone to date data type.
timestamptz_date(PG_FUNCTION_ARGS)
	TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
Bruce Momjian's avatar
Bruce Momjian committed
	struct pg_tm tt,
	if (TIMESTAMP_NOT_FINITE(timestamp))
	if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0)
		ereport(ERROR,
				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
				 errmsg("timestamp out of range")));
	result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
/* abstime_date()
 * Convert abstime to date data type.
Datum
abstime_date(PG_FUNCTION_ARGS)
	AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
Bruce Momjian's avatar
Bruce Momjian committed
	struct pg_tm tt,
	switch (abstime)
	{
		case INVALID_ABSTIME:
		case NOSTART_ABSTIME:
		case NOEND_ABSTIME:
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				   errmsg("cannot convert reserved abstime value to date")));
			 * pretend to drop through to make compiler think that result will
			 * be set
			 */

		default:
			abstime2tm(abstime, &tz, tm, NULL);
			result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
/* date_text()
 * Convert date to text data type.
 */
Datum
date_text(PG_FUNCTION_ARGS)
{
	/* Input is a Date, but may as well leave it in Datum form */
	Datum		date = PG_GETARG_DATUM(0);
	text	   *result;
	char	   *str;
	int			len;

	str = DatumGetCString(DirectFunctionCall1(date_out, date));

	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_date()
 * Convert text string to date.
 * Text type is not null terminated, so use temporary string
 *	then call the standard input routine.
 */
Datum
text_date(PG_FUNCTION_ARGS)
{
	text	   *str = PG_GETARG_TEXT_P(0);
	int			i;
	char	   *sp,
			   *dp,
				dstr[MAXDATELEN + 1];

	if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
				 errmsg("invalid input syntax for type date: \"%s\"",
Bruce Momjian's avatar
Bruce Momjian committed
						VARDATA(str))));

	sp = VARDATA(str);
	dp = dstr;
	for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
		*dp++ = *sp++;
	*dp = '\0';

	return DirectFunctionCall1(date_in,
							   CStringGetDatum(dstr));
}


/*****************************************************************************
 *	 Time ADT
 *****************************************************************************/
	char	   *str = PG_GETARG_CSTRING(0);
Bruce Momjian's avatar
Bruce Momjian committed

#ifdef NOT_USED
	Oid			typelem = PG_GETARG_OID(1);
#endif
	int32		typmod = PG_GETARG_INT32(2);
	TimeADT		result;
Bruce Momjian's avatar
Bruce Momjian committed
	struct pg_tm tt,
	char	   *field[MAXDATEFIELDS];
	int			dtype;
	int			ftype[MAXDATEFIELDS];
	dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
						  field, ftype, MAXDATEFIELDS, &nf);
	if (dterr == 0)
		dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
	if (dterr != 0)
		DateTimeParseError(dterr, str, "time");
/* tm2time()
 * Convert a tm structure to a time data type.
 */
tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result)
	*result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
			   * USECS_PER_SEC) + fsec;
	*result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
#endif
	return 0;
}

/* time2tm()
 * Convert time data type to POSIX time structure.
 * For dates within the system-supported time_t range, convert to the
 *	local time zone. If out of this range, leave as GMT. - tgl 97/05/27
 */
time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec)
	tm->tm_hour = time / USECS_PER_HOUR;
	time -= tm->tm_hour * USECS_PER_HOUR;
	tm->tm_min = time / USECS_PER_MINUTE;
	time -= tm->tm_min * USECS_PER_MINUTE;
	tm->tm_sec = time / USECS_PER_SEC;
	time -= tm->tm_sec * USECS_PER_SEC;
	TMODULO(trem, tm->tm_hour, (double) SECS_PER_HOUR);
	TMODULO(trem, tm->tm_min, (double) SECS_PER_MINUTE);
	TMODULO(trem, tm->tm_sec, 1.0);
	trem = TIMEROUND(trem);
	/* roundoff may need to propagate to higher-order fields */
	if (trem >= 1.0)
	{
		time = ceil(time);
		goto recalc;
	}
Datum
time_out(PG_FUNCTION_ARGS)
	TimeADT		time = PG_GETARG_TIMEADT(0);
Bruce Momjian's avatar
Bruce Momjian committed
	struct pg_tm tt,
	EncodeTimeOnly(tm, fsec, NULL, DateStyle, buf);
	result = pstrdup(buf);
	PG_RETURN_CSTRING(result);
}
/*
 *		time_recv			- converts external binary format to time
 *
 * We make no attempt to provide compatibility between int and float
 * time representations ...
 */
Datum
time_recv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
#ifdef NOT_USED
	Oid			typelem = PG_GETARG_OID(1);
#endif