mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
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.
This commit is contained in:
@@ -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() */
|
||||
|
||||
@@ -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:
|
||||
|
||||
/*
|
||||
* 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
|
||||
/* Previous field was a label for "julian date"?
|
||||
* then this should be a julian date with fractional day...
|
||||
*/
|
||||
if ((fmask & DTK_DATE_M) == DTK_DATE_M)
|
||||
if (ptype == JULIAN)
|
||||
{
|
||||
char *cp;
|
||||
double dt, date, time;
|
||||
|
||||
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
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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() )
|
||||
* ---------------------
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user