aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/dt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/dt.c')
-rw-r--r--src/backend/utils/adt/dt.c234
1 files changed, 97 insertions, 137 deletions
diff --git a/src/backend/utils/adt/dt.c b/src/backend/utils/adt/dt.c
index d700cbd6bd6..de0ec568544 100644
--- a/src/backend/utils/adt/dt.c
+++ b/src/backend/utils/adt/dt.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.19 1997/04/27 19:20:10 thomas Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.20 1997/05/11 15:11:34 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,7 +32,7 @@
#include "utils/builtins.h"
#define USE_DATE_CACHE 1
-
+#define ROUND_ALL 0
#define isleap(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
@@ -78,7 +78,8 @@ datetime_in(char *str)
switch (dtype) {
case DTK_DATE:
- *result = tm2datetime( tm, fsec, &tz);
+ if (tm2datetime( tm, fsec, &tz, result) != 0)
+ elog(WARN,"Datetime out of range %s",str);
#ifdef DATEDEBUG
printf( "datetime_in- date is %f\n", *result);
@@ -123,6 +124,7 @@ datetime_out(DateTime *dt)
int tz;
struct tm tt, *tm = &tt;
double fsec;
+ char *tzn;
char buf[MAXDATELEN+1];
if (!PointerIsValid(dt))
@@ -131,8 +133,8 @@ datetime_out(DateTime *dt)
if (DATETIME_IS_RESERVED(*dt)) {
EncodeSpecialDateTime(*dt, buf);
- } else if (datetime2tm( *dt, &tz, tm, &fsec) == 0) {
- EncodeDateTime(tm, fsec, &tz, DateStyle, buf);
+ } else if (datetime2tm( *dt, &tz, tm, &fsec, &tzn) == 0) {
+ EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
} else {
EncodeSpecialDateTime(DT_INVALID, buf);
@@ -179,7 +181,7 @@ timespan_in(char *str)
if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
|| (DecodeDateDelta( field, ftype, nf, &dtype, tm, &fsec) != 0))
- elog(WARN,"Bad timespan external representation %s",str);
+ elog(WARN,"Bad timespan external representation '%s'",str);
if (!PointerIsValid(span = PALLOCTYPE(TimeSpan)))
elog(WARN,"Memory allocation failed, can't input timespan '%s'",str);
@@ -190,6 +192,7 @@ timespan_in(char *str)
#if FALSE
TIMESPAN_INVALID(span);
#endif
+ elog(WARN,"Bad timespan external representation %s",str);
};
break;
@@ -292,14 +295,14 @@ SetDateTime( DateTime dt) {
if (DATETIME_IS_CURRENT(dt)) {
GetCurrentTime(&tt);
- dt = tm2datetime( &tt, 0, NULL);
+ tm2datetime( &tt, 0, NULL, &dt);
#ifdef DATEDEBUG
printf( "SetDateTime- current time is %f\n", dt);
#endif
} else { /* if (DATETIME_IS_EPOCH(dt1)) */
GetEpochTime(&tt);
- dt = tm2datetime( &tt, 0, NULL);
+ tm2datetime( &tt, 0, NULL, &dt);
#ifdef DATEDEBUG
printf( "SetDateTime- epoch time is %f\n", dt);
#endif
@@ -629,7 +632,7 @@ TimeSpan *datetime_sub(DateTime *datetime1, DateTime *datetime2)
DATETIME_INVALID( result->time);
} else {
- result->time = (dt1 - dt2);
+ result->time = JROUND(dt1 - dt2);
};
result->month = 0;
@@ -649,11 +652,6 @@ DateTime *datetime_add_span(DateTime *datetime, TimeSpan *span)
{
DateTime *result;
-#if FALSE
- double date, time;
- int year, mon, mday;
-#endif
-
if ((!PointerIsValid(datetime)) || (!PointerIsValid(span)))
return NULL;
@@ -677,7 +675,7 @@ printf( "datetime_add_span- add %f to %d %f\n", *datetime, span->month, span->ti
struct tm tt, *tm = &tt;
double fsec;
- if (datetime2tm( *result, NULL, tm, &fsec) == 0) {
+ if (datetime2tm( *result, NULL, tm, &fsec, NULL) == 0) {
#ifdef DATEDEBUG
printf( "datetime_add_span- date was %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday);
#endif
@@ -702,17 +700,18 @@ printf( "datetime_add_span- date was %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, t
#ifdef DATEDEBUG
printf( "datetime_add_span- date becomes %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday);
#endif
- *result = tm2datetime( tm, fsec, NULL);
+ tm2datetime( tm, fsec, NULL, result);
} else {
DATETIME_INVALID(*result);
};
};
-#if FALSE
+#ifdef ROUND_ALL
*result = JROUND(*result + span->time);
-#endif
+#else
*result += span->time;
+#endif
};
return(result);
@@ -1009,6 +1008,7 @@ datetime_part(text *units, DateTime *datetime)
int i;
char *up, *lp, lowunits[MAXDATELEN+1];
double fsec;
+ char *tzn;
struct tm tt, *tm = &tt;
if ((!PointerIsValid(units)) || (!PointerIsValid(datetime)))
@@ -1039,7 +1039,7 @@ printf( "datetime_part- units %s type=%d value=%d\n", lowunits, type, val);
dt = (DATETIME_IS_RELATIVE(*datetime)? SetDateTime(*datetime): *datetime);
- if (datetime2tm( dt, &tz, tm, &fsec) == 0) {
+ if (datetime2tm( dt, &tz, tm, &fsec, &tzn) == 0) {
switch (val) {
case DTK_TZ:
*result = tz;
@@ -1473,40 +1473,51 @@ datetkn *deltacache[MAXDATEFIELDS] = {NULL};
* Ref: Explanatory Supplement to the Astronomical Almanac, 1992.
* University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
*
+ * 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
*/
-#define USE_FLIEGEL 1
+/* Set the minimum year to one greater than the year of the first valid day
+ * to avoid having to check year and day both. - tgl 97/05/08
+ */
+
+#define UTIME_MINYEAR (1901)
+#define UTIME_MINMONTH (12)
+#define UTIME_MINDAY (14)
+#define UTIME_MAXYEAR (2038)
+#define UTIME_MAXMONTH (01)
+#define UTIME_MAXDAY (18)
+
+#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \
+ || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \
+ || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \
+ && ((y < UTIME_MAXYEAR) \
+ || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \
+ || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY))))))
+
+#define JULIAN_MINYEAR (-4713)
+#define JULIAN_MINMONTH (11)
+#define JULIAN_MINDAY (23)
+
+#define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \
+ || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \
+ || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY)))))
int
date2j(int y, int m, int d)
{
-#if USE_FLIEGEL
int m12 = (m-14)/12;
return((1461*(y+4800+m12))/4 + (367*(m-2-12*(m12)))/12
- (3*((y+4900+m12)/100))/4 + d - 32075);
-
-#else
- int c, ya;
-
- if (m > 2) {
- m -= 3;
- } else {
- m += 9;
- y--;
- };
- c = y/100;
- ya = y - 100*c;
- return((146097*c)/4+(1461*ya)/4+(153*m+2)/5+d+1721119);
-#endif
} /* date2j() */
void j2date( int jd, int *year, int *month, int *day)
{
int j, y, m, d;
-#if USE_FLIEGEL
int i, l, n;
l = jd + 68569;
@@ -1520,26 +1531,6 @@ void j2date( int jd, int *year, int *month, int *day)
m = (j+2) - (12*l);
y = 100*(n-49)+i+l;
-#else
- j = jd - 1721119;
- y = (4*j-1)/146097;
- j = 4*j-1-146097*y;
- d = j/4;
- j = (4*d+3)/1461;
- d = 4*d+3-1461*j;
- d = (d+4)/4;
- m = (5*d-3)/153;
- d = 5*d-3-153*m;
- d = (d+5)/5;
- y = 100*y+j;
- if (m < 10) {
- m += 3;
- } else {
- m -= 9;
- y++;
- };
-#endif
-
*year = y;
*month = m;
*day = d;
@@ -1560,25 +1551,34 @@ int j2day( int date)
* Convert datetime data type to POSIX time structure.
* Note that year is _not_ 1900-based, but is an explicit full value.
* Also, month is one-based, _not_ zero-based.
+ * Returns:
+ * 0 on success
+ * -1 on out of range
*/
int
-datetime2tm( DateTime dt, int *tzp, struct tm *tm, double *fsec)
+datetime2tm( DateTime dt, int *tzp, struct tm *tm, double *fsec, char **tzn)
{
- double date, time, sec;
+ double date, date0, time, sec;
time_t utime;
#ifdef USE_POSIX_TIME
struct tm *tx;
#endif
+
+ date0 = date2j(2000,1,1);
time = (modf( dt/86400, &date)*86400);
- date += date2j(2000,1,1);
+
if (time < 0) {
time += 86400;
date -= 1;
};
/* Julian day routine does not work for negative Julian days */
- if (date < 0) return -1;
+ if (date < -date0)
+ return -1;
+
+ /* add offset to go from J2000 back to standard Julian date */
+ date += date0;
#ifdef DATEDEBUG
printf( "datetime2tm- date is %f (%f %f)\n", dt, date, time);
@@ -1601,8 +1601,9 @@ printf( "datetime2tm- time is %02d:%02d:%02d %.7f\n", tm->tm_hour, tm->tm_min, t
if (tzp != NULL) {
/* XXX HACK to get time behavior compatible with Postgres v6.0 - tgl 97/04/07 */
- if ((tm->tm_year >= 1902) && (tm->tm_year < 2038)) {
- utime = (dt + (date2j(2000,1,1)-date2j(1970,1,1))*86400);
+ if (IS_VALID_UTIME( tm->tm_year, tm->tm_mon, tm->tm_mday)) {
+ utime = (dt + (date0-date2j(1970,1,1))*86400);
+
#ifdef USE_POSIX_TIME
tx = localtime(&utime);
#ifdef DATEDEBUG
@@ -1617,32 +1618,31 @@ printf( "datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02.0f %s %s dst=%d\n",
tm->tm_min = tx->tm_min;
tm->tm_sec = tx->tm_sec;
tm->tm_isdst = tx->tm_isdst;
+
#ifdef HAVE_INT_TIMEZONE
*tzp = (tm->tm_isdst? (timezone - 3600): timezone);
+ if (tzn != NULL) *tzn = tzname[(tm->tm_isdst > 0)];
+
#else /* !HAVE_INT_TIMEZONE */
*tzp = (tm->tm_isdst? (tm->tm_gmtoff - 3600): tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
+ if (tzn != NULL) *tzn = tm->tm_zone;
#endif
+
#else /* !USE_POSIX_TIME */
*tzp = CTimeZone; /* V7 conventions; don't know timezone? */
+ if (tzn != NULL) *tzn = CTZName;
#endif
} else {
*tzp = 0;
tm->tm_isdst = 0;
-#ifdef USE_POSIX_TIME
-#ifdef HAVE_INT_TIMEZONE
- tzname[0] = "GMT";
-#else /* !HAVE_INT_TIMEZONE */
- tm->tm_zone = "GMT";
-#endif
-#else /* !USE_POSIX_TIME */
- strcpy( CTZName, "GMT");
-#endif
+ if (tzn != NULL) *tzn = NULL;
};
dt = dt2local( dt, *tzp);
} else {
tm->tm_isdst = 0;
+ if (tzn != NULL) *tzn = NULL;
};
#ifdef DATEDEBUG
@@ -1666,26 +1666,25 @@ printf( "datetime2tm- timezone is %s; offset is %d (%d); daylight is %d\n",
* Note that year is _not_ 1900-based, but is an explicit full value.
* Also, month is one-based, _not_ zero-based.
*/
-DateTime
-tm2datetime( struct tm *tm, double fsec, int *tzp) {
+int
+tm2datetime( struct tm *tm, double fsec, int *tzp, DateTime *result) {
- DateTime result;
double date, time;
/* Julian day routines are not correct for negative Julian days */
- if ((date = date2j(tm->tm_year,tm->tm_mon,tm->tm_mday)) < 0)
+ if (! IS_VALID_JULIAN( tm->tm_year, tm->tm_mon, tm->tm_mday))
return(DT_INVALID);
- date -= date2j(2000,1,1);
+ date = date2j(tm->tm_year,tm->tm_mon,tm->tm_mday) - date2j(2000,1,1);
time = time2t(tm->tm_hour,tm->tm_min,(tm->tm_sec + fsec));
- result = (date*86400+time);
+ *result = (date*86400+time);
#ifdef DATEDEBUG
-printf( "tm2datetime- date is %f (%f %f %d)\n", result, date, time, (((tm->tm_hour*60)+tm->tm_min)*60+tm->tm_sec));
+printf( "tm2datetime- date is %f (%f %f %d)\n", *result, date, time, (((tm->tm_hour*60)+tm->tm_min)*60+tm->tm_sec));
printf( "tm2datetime- time is %f %02d:%02d:%02d %f\n", time, tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
#endif
- if (tzp != NULL) result = dt2local(result, -(*tzp));
+ if (tzp != NULL) *result = dt2local(*result, -(*tzp));
- return(result);
+ return 0;
} /* tm2datetime() */
@@ -1703,10 +1702,11 @@ timespan2tm(TimeSpan span, struct tm *tm, float8 *fsec)
tm->tm_mon = 0;
};
-#if FALSE
+#ifdef ROUND_ALL
time = JROUND(span.time);
-#endif
+#else
time = span.time;
+#endif
funit = modf( (time / 86400), &iunit);
tm->tm_mday = iunit;
@@ -1743,7 +1743,7 @@ printf( "tm2timespan- %d %f = %04d-%02d-%02d %02d:%02d:%02d %.2f\n", span->month
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
#endif
- return 1;
+ return 0;
} /* tm2timespan() */
@@ -2092,7 +2092,7 @@ printf( " %02d:%02d:%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) == DTK_DATE_M)
&& (tzp != NULL) && (! (fmask & DTK_M(TZ)))) {
- if ((tm->tm_year >= 1902) && (tm->tm_year < 2038)) {
+ if (IS_VALID_UTIME( tm->tm_year, tm->tm_mon, tm->tm_mday)) {
#ifdef USE_POSIX_TIME
tm->tm_year -= 1900;
tm->tm_mon -= 1;
@@ -2667,6 +2667,7 @@ printf( "DecodeDateDelta- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
#endif
switch (ftype[i]) {
case DTK_TIME:
+ /* already read in forward-scan above so return error */
#if FALSE
if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) return -1;
#endif
@@ -2916,47 +2917,27 @@ printf( "EncodeSpecialDateTime- unrecognized date\n");
/* EncodeDateTime()
* Encode date and time interpreted as local time.
*/
-int EncodeDateTime(struct tm *tm, double fsec, int *tzp, int style, char *str)
+int EncodeDateTime(struct tm *tm, double fsec, int *tzp, char **tzn, int style, char *str)
{
char mabbrev[4], dabbrev[4];
int day, hour, min;
double sec;
-#if defined(DATEDEBUG) && FALSE
- char buf[MAXDATELEN+1];
-#endif
sec = (tm->tm_sec + fsec);
-#if FALSE
- tm->tm_isdst = -1;
-#endif
-
#ifdef DATEDEBUG
#ifdef USE_POSIX_TIME
#ifdef HAVE_INT_TIMEZONE
printf( "EncodeDateTime- timezone is %s (%s); offset is %d (%d); daylight is %d (%d)\n",
- tzname[0], CTZName, *tzp, CTimeZone, tm->tm_isdst, CDayLight);
+ *tzn, tzname[0], *tzp, CTimeZone, tm->tm_isdst, CDayLight);
#else
printf( "EncodeDateTime- timezone is %s (%s); offset is %ld (%d); daylight is %d (%d)\n",
- tm->tm_zone, CTZName, (- tm->tm_gmtoff), CTimeZone, tm->tm_isdst, CDayLight);
+ *tzn, tm->tm_zone, (- tm->tm_gmtoff), CTimeZone, tm->tm_isdst, CDayLight);
#endif
#else
-printf( "EncodeDateTime- timezone is %s; offset is %d; daylight is %d\n",
- CTZName, CTimeZone, CDayLight);
-#endif
+printf( "EncodeDateTime- timezone is %s (%s); offset is %d; daylight is %d\n",
+ *tzn, CTZName, CTimeZone, CDayLight);
#endif
-
-#ifdef USE_POSIX_TIME
- /* XXX HACK to get time behavior compatible with Postgres v6.0 - tgl 97/04/07 */
- if ((tm->tm_year >= 1902) && (tm->tm_year < 2038)) {
- tm->tm_year -= 1900;
- tm->tm_mon -= 1;
- mktime(tm);
- tm->tm_year += 1900;
- tm->tm_mon += 1;
- } else {
- tm->tm_isdst = -1;
- };
#endif
day = date2j( tm->tm_year, tm->tm_mon, tm->tm_mday);
@@ -2980,7 +2961,7 @@ printf( "EncodeDateTime- day is %d\n", day);
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
sprintf( (str+17), ((fsec != 0)? "%05.2f": "%02.0f"), sec);
- if (tm->tm_isdst >= 0) {
+ if ((*tzn != NULL) && (tm->tm_isdst >= 0)) {
if (tzp != NULL) {
hour = -(*tzp / 3600);
min = ((abs(*tzp) / 60) % 60);
@@ -3012,16 +2993,9 @@ printf( "EncodeDateTime- day is %d\n", day);
sprintf( (str+5), "/%04d %02d:%02d:%05.2f",
tm->tm_year, tm->tm_hour, tm->tm_min, sec);
- if (tm->tm_isdst >= 0) {
-#ifdef USE_POSIX_TIME
-#ifdef HAVE_INT_TIMEZONE
- sprintf( (str+22), " %s", tzname[(tm->tm_isdst > 0)]);
-#else /* !HAVE_INT_TIMEZONE */
- sprintf( (str+22), " %s", tm->tm_zone);
-#endif
-#else /* !USE_POSIX_TIME */
- sprintf( (str+22), " %s", CTZName);
-#endif
+ if ((*tzn != NULL) && (tm->tm_isdst >= 0)) {
+ strcpy( (str+22), " ");
+ strcpy( (str+23), *tzn);
};
} else {
@@ -3041,16 +3015,9 @@ printf( "EncodeDateTime- day is %d\n", day);
sprintf( (str+10), " %02d:%02d:%05.2f %04d",
tm->tm_hour, tm->tm_min, sec, tm->tm_year);
- if (tm->tm_isdst >= 0) {
-#ifdef USE_POSIX_TIME
-#ifdef HAVE_INT_TIMEZONE
- sprintf( (str+27), " %s", tzname[(tm->tm_isdst > 0)]);
-#else
- sprintf( (str+27), " %s", tm->tm_zone);
-#endif
-#else
- sprintf( (str+27), " %s", CTZName);
-#endif
+ if ((*tzn != NULL) && (tm->tm_isdst >= 0)) {
+ strcpy( (str+27), " ");
+ strcpy( (str+28), *tzn);
};
} else {
@@ -3063,13 +3030,6 @@ printf( "EncodeDateTime- day is %d\n", day);
printf( "EncodeDateTime- date result is %s\n", str);
#endif
-#if defined(DATEDEBUG) && FALSE
- if (tm->tm_year >= 1000) tm->tm_year -= 1900;
- tm->tm_mon -= 1;
- strftime( buf, sizeof(buf), "%y.%m.%d %H:%M:%S %Z", tm);
-printf( "EncodeDateTime- strftime result is %s\n", buf);
-#endif
-
return(TRUE);
} /* EncodeDateTime() */