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 + -
显示快捷键?