date.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,274 行 · 第 1/4 页

C
2,274
字号
/*------------------------------------------------------------------------- * * date.c *	  implements DATE and TIME data types specified in SQL-92 standard * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.93.2.1 2004/06/13 17:17:48 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <ctype.h>#include <limits.h>#include <time.h>#include <float.h>#include "access/hash.h"#include "libpq/pqformat.h"#include "miscadmin.h"#include "utils/builtins.h"#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 / 3600, where timeval is double. */#ifdef __FAST_MATH__#error -ffast-math is known to break this code#endifstatic int	time2tm(TimeADT time, struct tm * tm, fsec_t *fsec);static int	timetz2tm(TimeTzADT *time, struct tm * tm, fsec_t *fsec, int *tzp);static int	tm2time(struct tm * tm, fsec_t fsec, TimeADT *result);static int	tm2timetz(struct tm * tm, fsec_t fsec, int tz, TimeTzADT *result);static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);/***************************************************************************** *	 Date ADT *****************************************************************************//* date_in() * Given date text string, convert to internal date format. */Datumdate_in(PG_FUNCTION_ARGS){	char	   *str = PG_GETARG_CSTRING(0);	DateADT		date;	fsec_t		fsec;	struct tm	tt,			   *tm = &tt;	int			tzp;	int			dtype;	int			nf;	int			dterr;	char	   *field[MAXDATEFIELDS];	int			ftype[MAXDATEFIELDS];	char		lowstr[MAXDATELEN + 1];	if (strlen(str) >= sizeof(lowstr))		dterr = DTERR_BAD_FORMAT;	else		dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);	if (dterr == 0)		dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);	if (dterr != 0)		DateTimeParseError(dterr, str, "date");	switch (dtype)	{		case DTK_DATE:			break;		case DTK_CURRENT:			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("date/time value \"current\" is no longer supported")));			GetCurrentDateTime(tm);			break;		case DTK_EPOCH:			GetEpochTime(tm);			break;		default:			DateTimeParseError(DTERR_BAD_FORMAT, str, "date");			break;	}	date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;	PG_RETURN_DATEADT(date);}/* date_out() * Given internal format date, convert to text string. */Datumdate_out(PG_FUNCTION_ARGS){	DateADT		date = PG_GETARG_DATEADT(0);	char	   *result;	struct tm	tt,			   *tm = &tt;	char		buf[MAXDATELEN + 1];	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 */Datumdate_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 */Datumdate_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));}Datumdate_eq(PG_FUNCTION_ARGS){	DateADT		dateVal1 = PG_GETARG_DATEADT(0);	DateADT		dateVal2 = PG_GETARG_DATEADT(1);	PG_RETURN_BOOL(dateVal1 == dateVal2);}Datumdate_ne(PG_FUNCTION_ARGS){	DateADT		dateVal1 = PG_GETARG_DATEADT(0);	DateADT		dateVal2 = PG_GETARG_DATEADT(1);	PG_RETURN_BOOL(dateVal1 != dateVal2);}Datumdate_lt(PG_FUNCTION_ARGS){	DateADT		dateVal1 = PG_GETARG_DATEADT(0);	DateADT		dateVal2 = PG_GETARG_DATEADT(1);	PG_RETURN_BOOL(dateVal1 < dateVal2);}Datumdate_le(PG_FUNCTION_ARGS){	DateADT		dateVal1 = PG_GETARG_DATEADT(0);	DateADT		dateVal2 = PG_GETARG_DATEADT(1);	PG_RETURN_BOOL(dateVal1 <= dateVal2);}Datumdate_gt(PG_FUNCTION_ARGS){	DateADT		dateVal1 = PG_GETARG_DATEADT(0);	DateADT		dateVal2 = PG_GETARG_DATEADT(1);	PG_RETURN_BOOL(dateVal1 > dateVal2);}Datumdate_ge(PG_FUNCTION_ARGS){	DateADT		dateVal1 = PG_GETARG_DATEADT(0);	DateADT		dateVal2 = PG_GETARG_DATEADT(1);	PG_RETURN_BOOL(dateVal1 >= dateVal2);}Datumdate_cmp(PG_FUNCTION_ARGS){	DateADT		dateVal1 = PG_GETARG_DATEADT(0);	DateADT		dateVal2 = PG_GETARG_DATEADT(1);	if (dateVal1 < dateVal2)		PG_RETURN_INT32(-1);	else if (dateVal1 > dateVal2)		PG_RETURN_INT32(1);	PG_RETURN_INT32(0);}Datumdate_larger(PG_FUNCTION_ARGS){	DateADT		dateVal1 = PG_GETARG_DATEADT(0);	DateADT		dateVal2 = PG_GETARG_DATEADT(1);	PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);}Datumdate_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. */Datumdate_mi(PG_FUNCTION_ARGS){	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. */Datumdate_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. */Datumdate_mii(PG_FUNCTION_ARGS){	DateADT		dateVal = PG_GETARG_DATEADT(0);	int32		days = PG_GETARG_INT32(1);	PG_RETURN_DATEADT(dateVal - days);}#if NOT_USED/* date_pl_interval() and date_mi_interval() are probably * better implmented by converting the input date * to timestamp without time zone. So that is what we do * in pg_proc.h - thomas 2002-03-11 *//* Add an interval to a date, giving a new date. * Must handle both positive and negative intervals. */Datumdate_pl_interval(PG_FUNCTION_ARGS){	DateADT		dateVal = PG_GETARG_DATEADT(0);	Interval   *span = PG_GETARG_INTERVAL_P(1);	struct tm	tt,			   *tm = &tt;	if (span->month != 0)	{		j2date(dateVal + POSTGRES_EPOCH_JDATE,			   &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));		tm->tm_mon += span->month;		dateVal = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;	}	if (span->time != 0)		dateVal += (span->time / 86400e0);	PG_RETURN_DATEADT(dateVal);}/* Subtract an interval from a date, giving a new date. * Must handle both positive and negative intervals. */Datumdate_mi_interval(PG_FUNCTION_ARGS){	DateADT		dateVal = PG_GETARG_DATEADT(0);	Interval   *span = PG_GETARG_INTERVAL_P(1);	struct tm	tt,			   *tm = &tt;	if (span->month != 0)	{		j2date(dateVal + POSTGRES_EPOCH_JDATE,			   &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));		tm->tm_mon -= span->month;		dateVal = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;	}	if (span->time != 0)		dateVal -= (span->time / 86400e0);	PG_RETURN_DATEADT(dateVal);}#endif/* date_timestamp() * Convert date to timestamp data type. */Datumdate_timestamp(PG_FUNCTION_ARGS){	DateADT		dateVal = PG_GETARG_DATEADT(0);	Timestamp	result;#ifdef HAVE_INT64_TIMESTAMP	/* date is days since 2000, timestamp is microseconds since same... */	result = dateVal * INT64CONST(86400000000);#else	/* date is days since 2000, timestamp is seconds since same... */	result = dateVal * 86400.0;#endif	PG_RETURN_TIMESTAMP(result);}/* timestamp_date() * Convert timestamp to date data type. */Datumtimestamp_date(PG_FUNCTION_ARGS){	Timestamp	timestamp = PG_GETARG_TIMESTAMP(0);	DateADT		result;	struct tm	tt,			   *tm = &tt;	fsec_t		fsec;	if (TIMESTAMP_NOT_FINITE(timestamp))		PG_RETURN_NULL();	if (timestamp2tm(timestamp, NULL, tm, &fsec, 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. */Datumdate_timestamptz(PG_FUNCTION_ARGS){	DateADT		dateVal = PG_GETARG_DATEADT(0);	TimestampTz result;	struct tm	tt,			   *tm = &tt;	j2date(dateVal + POSTGRES_EPOCH_JDATE,		   &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));	if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))	{		int			tz;		tm->tm_hour = 0;		tm->tm_min = 0;		tm->tm_sec = 0;		tz = DetermineLocalTimeZone(tm);#ifdef HAVE_INT64_TIMESTAMP		result = (dateVal * INT64CONST(86400000000))			+ (tz * INT64CONST(1000000));#else		result = dateVal * 86400.0 + tz;#endif	}	else	{		/* Outside of range for timezone support, so assume UTC */#ifdef HAVE_INT64_TIMESTAMP		result = (dateVal * INT64CONST(86400000000));#else		result = dateVal * 86400.0;#endif	}	PG_RETURN_TIMESTAMP(result);}/* timestamptz_date() * Convert timestamp with time zone to date data type. */Datumtimestamptz_date(PG_FUNCTION_ARGS){	TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);	DateADT		result;	struct tm	tt,			   *tm = &tt;	fsec_t		fsec;	int			tz;	char	   *tzn;	if (TIMESTAMP_NOT_FINITE(timestamp))		PG_RETURN_NULL();	if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 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);}/* abstime_date() * Convert abstime to date data type. */Datumabstime_date(PG_FUNCTION_ARGS){	AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);	DateADT		result;	struct tm	tt,			   *tm = &tt;	int			tz;	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;			break;	}	PG_RETURN_DATEADT(result);}/* date_text() * Convert date to text data type. */Datumdate_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. */Datumtext_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\"",						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 *****************************************************************************/Datumtime_in(PG_FUNCTION_ARGS){	char	   *str = PG_GETARG_CSTRING(0);#ifdef NOT_USED	Oid			typelem = PG_GETARG_OID(1);#endif	int32		typmod = PG_GETARG_INT32(2);	TimeADT		result;	fsec_t		fsec;	struct tm	tt,			   *tm = &tt;	int			tz;	int			nf;	int			dterr;	char		lowstr[MAXDATELEN + 1];	char	   *field[MAXDATEFIELDS];	int			dtype;	int			ftype[MAXDATEFIELDS];	if (strlen(str) >= sizeof(lowstr))		dterr = DTERR_BAD_FORMAT;	else		dterr = ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?