From e35b759fedc9f286a405f69b3e224d730ea0669a Mon Sep 17 00:00:00 2001 From: "Thomas G. Lockhart" Date: Fri, 16 May 1997 07:19:50 +0000 Subject: [PATCH] Fix datetime and abstime conversions to and from date. Bring optional new-storage date and time up to date and test. This new storage format should fix the "Sparc gcc -O2 bug". (Enable new code with USE_NEW_DATE and USE_NEW_TIME in dt.h) --- src/backend/utils/adt/datetime.c | 250 +++++++++++++++++++++++++------ 1 file changed, 207 insertions(+), 43 deletions(-) diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 3fa05b507f..128111c384 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.5 1997/05/11 15:11:31 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.6 1997/05/16 07:19:50 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -31,6 +31,19 @@ static int day_tab[2][12] = { #define isleap(y) (((y % 4) == 0 && (y % 100) != 0) || (y % 400) == 0) +#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)))))) /***************************************************************************** * Date ADT @@ -104,7 +117,7 @@ printf( "date_in- input string is %s\n", str); #if USE_NEW_DATE - date = (date2j(tm->tm_year,tm->tm_mon,tm->tm_mday) - date2j(2000,1,1)); + date = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000,1,1)); return(date); @@ -142,7 +155,7 @@ date_out(int4 dateVal) #if USE_NEW_DATE - j2date( (((int) date) + date2j(2000,1,1)), &year, &month, &day); + j2date( (date + date2j(2000,1,1)), &year, &month, &day); #else @@ -157,8 +170,7 @@ date_out(int4 dateVal) else sprintf(buf, "%02d-%02d-%04d", month, day, year); - if (!PointerIsValid(result = PALLOC(strlen(buf)+1))) - elog(WARN,"Memory allocation failed, can't output date",NULL); + result = PALLOC(strlen(buf)+1); strcpy( result, buf); @@ -167,6 +179,8 @@ date_out(int4 dateVal) #if USE_NEW_DATE +int date2tm(DateADT dateVal, int *tzp, struct tm *tm, double *fsec, char **tzn); + bool date_eq(DateADT dateVal1, DateADT dateVal2) { @@ -253,15 +267,26 @@ date_mii(DateADT dateVal, int4 days) * Convert date to datetime data type. */ DateTime * -date_datetime(int4 dateVal) +date_datetime(DateADT dateVal) { DateTime *result; + struct tm tt, *tm = &tt; + int tz; + double fsec = 0; + char *tzn; - if (!PointerIsValid(result = PALLOCTYPE(DateTime))) - elog(WARN,"Memory allocation failed, can't convert date to datetime",NULL); + result = PALLOCTYPE(DateTime); - *result = (dateVal - date2j( 2000, 1, 1)); - *result *= 86400; + if (date2tm( dateVal, &tz, tm, &fsec, &tzn) != 0) + elog(WARN,"Unable to convert date to datetime",NULL); + +#ifdef DATEDEBUG +printf( "date_datetime- date is %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday); +printf( "date_datetime- time is %02d:%02d:%02d %.7f\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec); +#endif + + if (tm2datetime( tm, fsec, &tz, result) != 0) + elog(WARN,"Datetime out of range",NULL); return(result); } /* date_datetime() */ @@ -274,11 +299,29 @@ DateADT datetime_date(DateTime *datetime) { DateADT result; + struct tm tt, *tm = &tt; + int tz; + double fsec; + char *tzn; if (!PointerIsValid(datetime)) elog(WARN,"Unable to convert null datetime to date",NULL); - result = (*datetime / 86400); + if (DATETIME_NOT_FINITE(*datetime)) + elog(WARN,"Unable to convert datetime to date",NULL); + + if (DATETIME_IS_EPOCH(*datetime)) { + datetime2tm( SetDateTime(*datetime), NULL, tm, &fsec, NULL); + + } else if (DATETIME_IS_CURRENT(*datetime)) { + datetime2tm( SetDateTime(*datetime), &tz, tm, &fsec, &tzn); + + } else { + if (datetime2tm( *datetime, &tz, tm, &fsec, &tzn) != 0) + elog(WARN,"Unable to convert datetime to date",NULL); + }; + + result = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j( 2000, 1, 1)); return(result); } /* datetime_date() */ @@ -291,14 +334,15 @@ DateADT abstime_date(AbsoluteTime abstime) { DateADT result; - struct tt, *tm = &tt; + struct tm tt, *tm = &tt; + int tz; switch (abstime) { case INVALID_ABSTIME: case NOSTART_ABSTIME: case NOEND_ABSTIME: elog(WARN,"Unable to convert reserved abstime value to date",NULL); - break; + /* pretend to drop through to make compiler think that result will be set */ case EPOCH_ABSTIME: result = date2j(1970,1,1) - date2j(2000,1,1); @@ -306,17 +350,11 @@ abstime_date(AbsoluteTime abstime) case CURRENT_ABSTIME: GetCurrentTime(tm); - result = date2j(tm->tm_year,tm->tm_mon,tm->tm_mday) - date2j(2000,1,1); + result = date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000,1,1); break; default: -#if FALSE - tm = localtime((time_t *) &abstime); - tm->tm_year += 1900; - tm->tm_mon += 1; - /* XXX must shift to local time before converting - tgl 97/04/01 */ -#endif - abstime2tm(abstime, &CTimeZone, tm); + abstime2tm(abstime, &tz, tm); result = date2j(tm->tm_year,tm->tm_mon,tm->tm_mday) - date2j(2000,1,1); break; }; @@ -324,6 +362,86 @@ abstime_date(AbsoluteTime abstime) return(result); } /* abstime_date() */ + +/* date2tm() + * Convert date to time structure. + * Note that date is an implicit local time, but the system calls assume + * that everything is GMT. So, convert to GMT, rotate to local time, + * and then convert again to try to get the time zones correct. + */ +int +date2tm(DateADT dateVal, int *tzp, struct tm *tm, double *fsec, char **tzn) +{ + struct tm *tx; + time_t utime; + *fsec = 0; + + j2date( (dateVal + date2j( 2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + tm->tm_isdst = -1; + + if (IS_VALID_UTIME( tm->tm_year, tm->tm_mon, tm->tm_mday)) { + + /* convert to system time */ + utime = ((dateVal + (date2j(2000,1,1)-date2j(1970,1,1)))*86400); + utime += (12*60*60); /* rotate to noon to get the right day in time zone */ + +#ifdef USE_POSIX_TIME + tx = localtime(&utime); + +#ifdef DATEDEBUG +printf( "date2tm- (localtime) %d.%02d.%02d %02d:%02d:%02.0f %s %s dst=%d\n", + tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, sec, + tzname[0], tzname[1], tx->tm_isdst); +#endif + tm->tm_year = tx->tm_year + 1900; + tm->tm_mon = tx->tm_mon + 1; + tm->tm_mday = tx->tm_mday; +#if FALSE + tm->tm_hour = tx->tm_hour; + tm->tm_min = tx->tm_min; + tm->tm_sec = tx->tm_sec; +#endif + 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 + + /* otherwise, outside of timezone range so convert to GMT... */ + } else { +#if FALSE + j2date( (dateVal + date2j( 2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; +#endif + +#ifdef DATEDEBUG +printf( "date2tm- convert %d-%d-%d %d:%d%d to datetime\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); +#endif + + *tzp = 0; + tm->tm_isdst = 0; + if (tzn != NULL) *tzn = NULL; + }; + + return 0; +} /* date2tm() */ + #else bool @@ -502,11 +620,22 @@ date_datetime(int4 dateVal) DateTime *result; DateADT *date = (DateADT *) &dateVal; - if (!PointerIsValid(result = PALLOCTYPE(DateTime))) - elog(WARN,"Memory allocation failed, can't convert date to datetime",NULL); + int tz; + double fsec; + char *tzn; + struct tm tt, *tm = &tt; + + result = PALLOCTYPE(DateTime); *result = (date2j(date->year, date->month, date->day) - date2j( 2000, 1, 1)); *result *= 86400; + *result += (12*60*60); + + datetime2tm( *result, &tz, tm, &fsec, &tzn); + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + tm2datetime( tm, fsec, &tz, result); #ifdef DATEDEBUG printf( "date_datetime- convert %04d-%02d-%02d to %f\n", @@ -520,16 +649,32 @@ int4 datetime_date(DateTime *datetime) { int4 result; - int year, month, day; + int tz; + double fsec; + char *tzn; + struct tm tt, *tm = &tt; DateADT *date = (DateADT *) &result; if (!PointerIsValid(datetime)) elog(WARN,"Unable to convert null datetime to date",NULL); - j2date( ((*datetime / 86400) + date2j( 2000, 1, 1)), &year, &month, &day); - date->year = year; - date->month = month; - date->day = day; + if (DATETIME_NOT_FINITE(*datetime)) + elog(WARN,"Unable to convert datetime to date",NULL); + + if (DATETIME_IS_EPOCH(*datetime)) { + datetime2tm( SetDateTime(*datetime), NULL, tm, &fsec, NULL); + + } else if (DATETIME_IS_CURRENT(*datetime)) { + datetime2tm( SetDateTime(*datetime), &tz, tm, &fsec, &tzn); + + } else { + if (datetime2tm( *datetime, &tz, tm, &fsec, &tzn) != 0) + elog(WARN,"Unable to convert datetime to date",NULL); + }; + + date->year = tm->tm_year; + date->month = tm->tm_mon; + date->day = tm->tm_mday; return(result); } /* datetime_date() */ @@ -539,6 +684,7 @@ abstime_date(AbsoluteTime abstime) { int4 result; DateADT *date = (DateADT *) &result; + int tz; struct tm tt, *tm = &tt; switch (abstime) { @@ -555,11 +701,8 @@ abstime_date(AbsoluteTime abstime) break; case CURRENT_ABSTIME: -#if FALSE - GetCurrentTime(tm); -#endif abstime = GetCurrentTransactionStartTime(); - abstime2tm(abstime, &CTimeZone, tm); + abstime2tm(abstime, &tz, tm); date->year = tm->tm_year; date->month = tm->tm_mon; date->day = tm->tm_mday; @@ -571,7 +714,7 @@ abstime_date(AbsoluteTime abstime) tm->tm_year += 1900; tm->tm_mon += 1; #endif - abstime2tm(abstime, &CTimeZone, tm); + abstime2tm(abstime, &tz, tm); date->year = tm->tm_year; date->month = tm->tm_mon; date->day = tm->tm_mday; @@ -617,8 +760,7 @@ time_in(char *str) if ((tm->tm_sec < 0) || ((tm->tm_sec + fsec) >= 60)) elog(WARN,"Second must be limited to values 0 through < 60 in '%s'",str); - if (!PointerIsValid(time = PALLOCTYPE(TimeADT))) - elog(WARN,"Memory allocation failed, can't input time '%s'",str); + time = PALLOCTYPE(TimeADT); #if USE_NEW_TIME @@ -640,11 +782,36 @@ char * time_out(TimeADT *time) { char *result; +#if USE_NEW_TIME + int hour, min, sec; + double fsec; +#endif char buf[32]; if (!PointerIsValid(time)) return NULL; +#if USE_NEW_TIME + + hour = (*time / (60*60)); + min = (((int) (*time / 60)) % 60); + sec = (((int) *time) % 60); + + fsec = 0; + + if (sec == 0.0) { + sprintf(buf, "%02d:%02d", hour, min); + + } else { + if (fsec == 0) { + sprintf(buf, "%02d:%02d:%02d", hour, min, sec); + } else { + sprintf(buf, "%02d:%02d:%05.2f", hour, min, (sec+fsec)); + }; + }; + +#else + if (time->sec == 0.0) { sprintf(buf, "%02d:%02d", (int)time->hr, (int)time->min); } else { @@ -657,8 +824,9 @@ time_out(TimeADT *time) }; }; - if (!PointerIsValid(result = PALLOC(strlen(buf)+1))) - elog(WARN,"Memory allocation failed, can't output time",NULL); +#endif + + result = PALLOC(strlen(buf)+1); strcpy( result, buf); @@ -738,9 +906,7 @@ datetime_datetime(DateADT date, TimeADT *time) DateTime *result; if (!PointerIsValid(time)) { - if (!PointerIsValid(result = PALLOCTYPE(DateTime))) - elog(WARN,"Memory allocation failed, can't convert to datetime",NULL); - + result = PALLOCTYPE(DateTime); DATETIME_INVALID(*result); } else { @@ -828,9 +994,7 @@ datetime_datetime(int4 dateVal, TimeADT *time) #endif if (!PointerIsValid(time)) { - if (!PointerIsValid(result = PALLOCTYPE(DateTime))) - elog(WARN,"Memory allocation failed, can't convert to datetime",NULL); - + result = PALLOCTYPE(DateTime); DATETIME_INVALID(*result); } else { -- 2.40.0