Commit dfe04753 authored by Marc G. Fournier's avatar Marc G. Fournier

From: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov>

Subject: [HACKERS] More patches for date/time

I have accumulated several patches to add functionality to the datetime
and timespan data types as well as to fix reported porting bugs on non-BSD
machines. These patches are:

dt.c.patch              - add datetime_part(), fix bugs
dt.h.patch              - add quarter and timezone support, add prototypes
globals.c.patch         - add time and timezone variables
miscadmin.h.patch       - add time and timezone variables
nabstime.c.patch        - add datetime conversion routine
nabstime.h.patch        - add prototypes
pg_operator.h.patch     - add datetime operators, clean up formatting
pg_proc.h.patch         - add datetime functions, reassign conflicting date OIDs
pg_type.h.patch         - add datetime and timespan data types

The dt.c and pg_proc.h patches are fairly large; the latter mostly because I tried
to get some columns for existing entries to line up.
parent d2a386d6
This diff is collapsed.
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.16 1997/03/21 18:53:28 scrappy Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.17 1997/03/25 08:09:35 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -62,13 +62,13 @@ GetCurrentAbsoluteTime(void)
CTimeZone = - tmnow->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
CDayLight = (tmnow->tm_isdst > 0);
/* XXX is there a better way to get local timezone string in V7? - tgl 97/03/18 */
strftime( CTZName, 8, "%Z", localtime(&now));
strftime( CTZName, MAXTZLEN, "%Z", localtime(&now));
#endif
#else /* ! USE_POSIX_TIME */
CTimeZone = tbnow.timezone * 60;
CDayLight = (tbnow.dstflag != 0);
/* XXX does this work to get the local timezone string in V7? - tgl 97/03/18 */
strftime( CTZName, 8, "%Z", localtime(&now));
strftime( CTZName, MAXTZLEN, "%Z", localtime(&now));
#endif
};
......@@ -102,15 +102,61 @@ GetCurrentTime(struct tm *tm)
} /* GetCurrentTime() */
AbsoluteTime tm2abstime( struct tm *tm, int tz);
AbsoluteTime
tm2abstime( struct tm *tm, int tz)
{
int day, sec;
/* validate, before going out of range on some members */
if (tm->tm_year < 1901 || tm->tm_year > 2038
|| tm->tm_mon < 1 || tm->tm_mon > 12
|| tm->tm_mday < 1 || tm->tm_mday > 31
|| tm->tm_hour < 0 || tm->tm_hour >= 24
|| tm->tm_min < 0 || tm->tm_min > 59
|| tm->tm_sec < 0 || tm->tm_sec > 59)
return INVALID_ABSTIME;
day = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j( 1970, 1, 1));
/* check for time out of range */
if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
return INVALID_ABSTIME;
/* convert to seconds */
sec = tm->tm_sec + tz + (tm->tm_min +(day*24 + tm->tm_hour)*60)*60;
/* check for overflow */
if ((day == MAX_DAYNUM && sec < 0) ||
(day == MIN_DAYNUM && sec > 0))
return INVALID_ABSTIME;
/* daylight correction */
if (tm->tm_isdst < 0) { /* unknown; find out */
tm->tm_isdst = (CDayLight > 0);
};
if (tm->tm_isdst > 0)
sec -= 60*60;
/* check for reserved values (e.g. "current" on edge of usual range */
if (!AbsoluteTimeIsReal(sec))
return INVALID_ABSTIME;
return sec;
} /* tm2abstime() */
/* nabstimein()
* Decode date/time string and return abstime.
*/
AbsoluteTime
nabstimein(char* str)
{
int sec;
AbsoluteTime result;
double fsec;
int day, tz = 0;
int tz = 0;
struct tm date, *tm = &date;
char *field[MAXDATEFIELDS];
......@@ -134,65 +180,35 @@ printf( "nabstimein- %d fields are type %d (DTK_DATE=%d)\n", nf, dtype, DTK_DATE
switch (dtype) {
case DTK_DATE:
#if FALSE
return(dateconv( &date, tz));
#endif
/* validate, before going out of range on some members */
if (tm->tm_year < 1901 || tm->tm_year > 2038
|| tm->tm_mon < 1 || tm->tm_mon > 12
|| tm->tm_mday < 1 || tm->tm_mday > 31
|| tm->tm_hour < 0 || tm->tm_hour >= 24
|| tm->tm_min < 0 || tm->tm_min > 59
|| tm->tm_sec < 0 || tm->tm_sec > 59)
return INVALID_ABSTIME;
day = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j( 1970, 1, 1));
/* check for time out of range */
if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
return INVALID_ABSTIME;
/* convert to seconds */
sec = tm->tm_sec + tz + (tm->tm_min +(day*24 + tm->tm_hour)*60)*60;
/* check for overflow */
if ((day == MAX_DAYNUM && sec < 0) ||
(day == MIN_DAYNUM && sec > 0))
return INVALID_ABSTIME;
/* daylight correction */
if (tm->tm_isdst < 0) { /* unknown; find out */
tm->tm_isdst = (CDayLight > 0);
};
if (tm->tm_isdst > 0)
sec -= 60*60;
/* check for reserved values (e.g. "current" on edge of usual range */
if (!AbsoluteTimeIsReal(sec))
return INVALID_ABSTIME;
return sec;
result = tm2abstime(tm, tz);
break;
case DTK_EPOCH:
return EPOCH_ABSTIME;
result = EPOCH_ABSTIME;
break;
case DTK_CURRENT:
return CURRENT_ABSTIME;
result = CURRENT_ABSTIME;
break;
case DTK_LATE:
return NOEND_ABSTIME;
result = NOEND_ABSTIME;
break;
case DTK_EARLY:
return NOSTART_ABSTIME;
result = NOSTART_ABSTIME;
break;
case DTK_INVALID:
return INVALID_ABSTIME;
result = INVALID_ABSTIME;
break;
default:
elog(WARN,"Bad abstime (internal coding error) '%s'",str);
result = INVALID_ABSTIME;
};
elog(WARN,"Bad abstime (internal coding error) '%s'",str);
return INVALID_ABSTIME;
return result;
} /* nabstimein() */
......@@ -432,3 +448,42 @@ abstimege(AbsoluteTime t1, AbsoluteTime t2)
return(t1 >= t2);
}
/* datetime_abstime()
* Convert datetime to abstime.
*/
AbsoluteTime
datetime_abstime(DateTime *datetime)
{
AbsoluteTime result;
double fsec;
struct tm tt, *tm = &tt;
if (!PointerIsValid(datetime)) {
result = INVALID_ABSTIME;
} else if (DATETIME_IS_INVALID(*datetime)) {
result = INVALID_ABSTIME;
} else if (DATETIME_IS_NOBEGIN(*datetime)) {
result = NOSTART_ABSTIME;
} else if (DATETIME_IS_NOEND(*datetime)) {
result = NOEND_ABSTIME;
} else {
if (DATETIME_IS_RELATIVE(*datetime)) {
datetime2tm( SetDateTime(*datetime), tm, &fsec);
result = tm2abstime( tm, 0);
} else if (datetime2tm( *datetime, tm, &fsec) == 0) {
result = tm2abstime( tm, 0);
} else {
result = INVALID_ABSTIME;
};
};
return(result);
} /* datetime_abstime() */
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.7 1997/03/18 20:14:46 scrappy Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.8 1997/03/25 08:09:43 scrappy Exp $
*
* NOTES
* Globals used all over the place should be declared here and not
......@@ -65,11 +65,12 @@ bool IsPostmaster = false;
short DebugLvl = 0;
int DateStyle = USE_ISO_DATES;
bool EuroDates = false;
bool HasCTZSet = false;
bool CDayLight = false;
int CTimeZone = 0;
char CTZName[8] = "";
char CTZName[MAXTZLEN+1] = "";
char DateFormat[20] = "%d-%m-%Y"; /* mjl: sizes! or better malloc? XXX */
char FloatFormat[20] = "%f";
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -11,7 +11,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: miscadmin.h,v 1.7 1997/03/18 20:15:19 scrappy Exp $
* $Id: miscadmin.h,v 1.8 1997/03/25 08:09:59 scrappy Exp $
*
* NOTES
* some of the information in this file will be moved to
......@@ -58,12 +58,28 @@ extern bool IsPostmaster;
extern short DebugLvl;
/* Date/Time Configuration
* HasCTZSet if client timezone is specified by client.
*
* Constants to pass info from runtime environment:
* USE_POSTGRES_DATES specifies traditional postgres format for output.
* USE_ISO_DATES specifies ISO-compliant format for output.
* USE_SQL_DATES specified Oracle/Ingres-compliant format for output.
*
* DateStyle specifies preference for date formatting for output.
* EuroDates if client prefers dates interpreted and written w/European conventions.
*
* HasCTZSet if client timezone is specified by client.
* CDayLight is the apparent daylight savings time status.
* CTimeZone is the timezone offset in seconds.
* CTZName is the timezone label.
*/
#define MAXTZLEN 7
#define USE_POSTGRES_DATES 0
#define USE_ISO_DATES 1
#define USE_SQL_DATES 2
extern int DateStyle;
extern bool EuroDates;
extern bool HasCTZSet;
extern bool CDayLight;
......
......@@ -8,7 +8,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: dt.h,v 1.2 1997/03/18 16:36:50 scrappy Exp $
* $Id: dt.h,v 1.3 1997/03/25 08:11:18 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -16,19 +16,23 @@
#define DT_H
#include <time.h>
#include <math.h>
/*
* DateTime represents absolute time.
* TimeSpan represents delta time.
* TimeSpan represents delta time. Keep track of months (and years)
* separately since the elapsed time spanned is unknown until instantiated
* relative to an absolute time.
*
* Note that Postgres uses "time interval" to mean a bounded interval,
* consisting of a beginning and ending time, not a time span.
* consisting of a beginning and ending time, not a time span - tgl 97/03/20
*/
typedef double DateTime;
typedef struct {
double time; /* all time units other than months and years */
int4 month; /* months and years */
int4 month; /* months and years, after time for alignment */
} TimeSpan;
......@@ -45,6 +49,7 @@ typedef struct {
* Other alternate forms are hardcoded into token tables in dt.c.
* ----------------------------------------------------------------
*/
#define DAGO "ago"
#define DCURRENT "current"
#define EPOCH "epoch"
......@@ -65,12 +70,14 @@ typedef struct {
#define DDAY "day"
#define DWEEK "week"
#define DMONTH "month"
#define DQUARTER "quarter"
#define DYEAR "year"
#define DDECADE "decade"
#define DCENTURY "century"
#define DMILLENIUM "millenium"
#define DA_D "ad"
#define DB_C "bc"
#define DTIMEZONE "timezone"
/*
* Fundamental time field definitions for parsing.
......@@ -78,6 +85,7 @@ typedef struct {
* Meridian: am, pm, or 24-hour style.
* Millenium: ad, bc
*/
#define AM 0
#define PM 1
#define HR24 2
......@@ -90,6 +98,7 @@ typedef struct {
* Can't have more of these than there are bits in an unsigned int
* since these are turned into bit masks during parsing and decoding.
*/
#define RESERV 0
#define MONTH 1
#define YEAR 2
......@@ -116,6 +125,7 @@ typedef struct {
* These need to fit into the datetkn table type.
* At the moment, that means keep them within [-127,127].
*/
#define DTK_NUMBER 0
#define DTK_STRING 1
......@@ -143,17 +153,19 @@ typedef struct {
#define DTK_DAY 36
#define DTK_WEEK 37
#define DTK_MONTH 38
#define DTK_YEAR 39
#define DTK_DECADE 40
#define DTK_CENTURY 41
#define DTK_MILLENIUM 42
#define DTK_MILLISEC 43
#define DTK_MICROSEC 44
#define DTK_AGO 45
#define DTK_QUARTER 39
#define DTK_YEAR 40
#define DTK_DECADE 41
#define DTK_CENTURY 42
#define DTK_MILLENIUM 43
#define DTK_MILLISEC 44
#define DTK_MICROSEC 45
#define DTK_AGO 46
/*
* Bit mask definitions for time parsing.
*/
#define DTK_M(t) (0x01 << t)
#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
......@@ -174,21 +186,95 @@ typedef struct {
char value; /* this may be unsigned, alas */
} datetkn;
extern void GetCurrentTime(struct tm *tm);
#ifdef NAN
#define DT_INVALID (NAN)
#else
#define DT_INVALID (DBL_MIN+DBL_MIN)
#endif
#ifdef HUGE_VAL
#define DT_NOBEGIN (-HUGE_VAL)
#define DT_NOEND (HUGE_VAL)
#else
#define DT_NOBEGIN (-DBL_MAX)
#define DT_NOEND (DBL_MAX)
#endif
#define DT_CURRENT (DBL_MIN)
#define DT_EPOCH (-DBL_MIN)
#define DATETIME_INVALID(j) {j = DT_INVALID;}
#ifdef NAN
#define DATETIME_IS_INVALID(j) (isnan(j))
#else
#define DATETIME_IS_INVALID(j) (j == DT_INVALID)
#endif
#define DATETIME_NOBEGIN(j) {j = DT_NOBEGIN;}
#define DATETIME_IS_NOBEGIN(j) (j == DT_NOBEGIN)
#define DATETIME_NOEND(j) {j = DT_NOEND;}
#define DATETIME_IS_NOEND(j) (j == DT_NOEND)
#define DATETIME_CURRENT(j) {j = DT_CURRENT;}
#define DATETIME_IS_CURRENT(j) (j == DT_CURRENT)
#define DATETIME_EPOCH(j) {j = DT_EPOCH;}
#define DATETIME_IS_EPOCH(j) (j == DT_EPOCH)
#define DATETIME_IS_RELATIVE(j) (DATETIME_IS_CURRENT(j) || DATETIME_IS_EPOCH(j))
#define DATETIME_NOT_FINITE(j) (DATETIME_IS_INVALID(j) \
|| DATETIME_IS_NOBEGIN(j) || DATETIME_IS_NOEND(j))
#define DATETIME_IS_RESERVED(j) (DATETIME_IS_RELATIVE(j) || DATETIME_NOT_FINITE(j))
#define TIMESPAN_INVALID(j) {j->time = DT_INVALID;}
#ifdef NAN
#define TIMESPAN_IS_INVALID(j) (isnan((j).time))
#else
#define TIMESPAN_IS_INVALID(j) ((j).time == DT_INVALID)
#endif
#define TIME_PREC 1e-6
#define JROUND(j) (rint(((double) j)/TIME_PREC)*TIME_PREC)
/*
* dt.c prototypes
*/
extern DateTime *datetime_in( char *str);
extern char *datetime_out( DateTime *dt);
extern bool datetime_eq(DateTime *dt1, DateTime *dt2);
extern bool datetime_ne(DateTime *dt1, DateTime *dt2);
extern bool datetime_lt(DateTime *dt1, DateTime *dt2);
extern bool datetime_le(DateTime *dt1, DateTime *dt2);
extern bool datetime_ge(DateTime *dt1, DateTime *dt2);
extern bool datetime_gt(DateTime *dt1, DateTime *dt2);
extern TimeSpan *timespan_in(char *str);
extern char *timespan_out(TimeSpan *span);
extern bool timespan_eq(TimeSpan *span1, TimeSpan *span2);
extern bool timespan_ne(TimeSpan *span1, TimeSpan *span2);
extern bool timespan_lt(TimeSpan *span1, TimeSpan *span2);
extern bool timespan_le(TimeSpan *span1, TimeSpan *span2);
extern bool timespan_ge(TimeSpan *span1, TimeSpan *span2);
extern bool timespan_gt(TimeSpan *span1, TimeSpan *span2);
float64 datetime_part(text *units, DateTime *datetime);
float64 timespan_part(text *units, TimeSpan *timespan);
extern TimeSpan *timespan_um(TimeSpan *span);
extern TimeSpan *timespan_add(TimeSpan *span1, TimeSpan *span2);
extern TimeSpan *timespan_sub(TimeSpan *span1, TimeSpan *span2);
extern TimeSpan *datetime_sub(DateTime *dt1, DateTime *dt2);
extern DateTime *datetime_add_span(DateTime *dt, TimeSpan *span);
extern DateTime *datetime_sub_span(DateTime *dt, TimeSpan *span);
extern TimeSpan *timespan_add(TimeSpan *span1, TimeSpan *span2);
extern TimeSpan *timespan_sub(TimeSpan *span1, TimeSpan *span2);
extern void GetCurrentTime(struct tm *tm);
DateTime SetDateTime(DateTime datetime);
DateTime tm2datetime(struct tm *tm, double fsec, int tzp);
int datetime2tm( DateTime dt, struct tm *tm, double *fsec);
int timespan2tm(TimeSpan span, struct tm *tm, float8 *fsec);
int tm2timespan(struct tm *tm, double fsec, TimeSpan *span);
extern DateTime dt2local( DateTime dt, int timezone);
......@@ -199,12 +285,8 @@ extern int j2day( int jd);
extern double time2t(const int hour, const int min, const double sec);
extern void dt2time(DateTime dt, int *hour, int *min, double *sec);
/*
extern void GetCurrentTime(struct tm *tm);
*/
extern int ParseDateTime( char *timestr, char *lowstr,
char *field[], int ftype[], int maxfields, int *numfields);
extern int DecodeDateTime( char *field[], int ftype[],
int nf, int *dtype, struct tm *tm, double *fsec, int *tzp);
extern int DecodeDate(char *str, int fmask, int *tmask, struct tm *tm);
......@@ -223,11 +305,10 @@ extern int DecodeDateDelta( char *field[], int ftype[],
int nf, int *dtype, struct tm *tm, double *fsec);
extern int DecodeUnits(int field, char *lowtoken, int *val);
extern int EncodeSpecialDateTime(DateTime *dt, char *str);
extern int EncodeSpecialDateTime(DateTime dt, char *str);
extern int EncodePostgresDate(struct tm *tm, double fsec, char *str);
extern int EncodePostgresSpan(struct tm *tm, double fsec, char *str);
extern datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
#endif /* DT_H */
......@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: nabstime.h,v 1.5 1997/03/14 23:33:29 scrappy Exp $
* $Id: nabstime.h,v 1.6 1997/03/25 08:11:24 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -115,8 +115,6 @@ extern AbsoluteTime GetCurrentAbsoluteTime(void);
extern AbsoluteTime nabstimein(char *timestr);
extern char *nabstimeout(AbsoluteTime time);
extern bool AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2);
extern bool AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2);
extern bool abstimeeq(AbsoluteTime t1, AbsoluteTime t2);
extern bool abstimene(AbsoluteTime t1, AbsoluteTime t2);
extern bool abstimelt(AbsoluteTime t1, AbsoluteTime t2);
......@@ -124,6 +122,10 @@ extern bool abstimegt(AbsoluteTime t1, AbsoluteTime t2);
extern bool abstimele(AbsoluteTime t1, AbsoluteTime t2);
extern bool abstimege(AbsoluteTime t1, AbsoluteTime t2);
extern AbsoluteTime datetime_abstime(DateTime *datetime);
extern bool AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2);
extern bool AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2);
extern AbsoluteTime dateconv(struct tm *tm, int zone);
extern time_t qmktime(struct tm *tp);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment