diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c index 6c9481b4b2..119c45093e 100644 --- a/contrib/btree_gist/btree_ts.c +++ b/contrib/btree_gist/btree_ts.c @@ -122,9 +122,7 @@ tstz_to_ts_gmt(Timestamp *gmt, TimestampTz *ts) *gmt -= (tz * INT64CONST(1000000)); #else *gmt -= tz; - *gmt = JROUND(*gmt); #endif - } return gmt; } diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index b36ee18092..ec1d808544 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.120 2005/09/09 02:31:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.121 2005/10/09 17:21:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -944,10 +944,18 @@ time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec) #else double trem; +recalc: trem = time; TMODULO(trem, tm->tm_hour, (double)SECS_PER_HOUR); TMODULO(trem, tm->tm_min, (double)SECS_PER_MINUTE); TMODULO(trem, tm->tm_sec, 1.0); + trem = TIMEROUND(trem); + /* roundoff may need to propagate to higher-order fields */ + if (trem >= 1.0) + { + time = ceil(time); + goto recalc; + } *fsec = trem; #endif @@ -1837,9 +1845,17 @@ timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp) #else double trem = time->time; +recalc: TMODULO(trem, tm->tm_hour, (double)SECS_PER_HOUR); TMODULO(trem, tm->tm_min, (double)SECS_PER_MINUTE); TMODULO(trem, tm->tm_sec, 1.0); + trem = TIMEROUND(trem); + /* roundoff may need to propagate to higher-order fields */ + if (trem >= 1.0) + { + trem = ceil(time->time); + goto recalc; + } *fsec = trem; #endif diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 9e5be7d4cf..74dda5441f 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.157 2005/07/23 14:25:33 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.158 2005/10/09 17:21:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -3488,8 +3488,8 @@ EncodeTimeOnly(struct pg_tm *tm, fsec_t fsec, int *tzp, int style, char *str) sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min); /* - * Print fractional seconds if any. The field widths here should be - * at least equal to the larger of MAX_TIME_PRECISION and + * Print fractional seconds if any. The fractional field widths + * here should be equal to the larger of MAX_TIME_PRECISION and * MAX_TIMESTAMP_PRECISION. */ if (fsec != 0) @@ -3497,7 +3497,7 @@ EncodeTimeOnly(struct pg_tm *tm, fsec_t fsec, int *tzp, int style, char *str) #ifdef HAVE_INT64_TIMESTAMP sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec); #else - sprintf(str + strlen(str), ":%012.9f", tm->tm_sec + fsec); + sprintf(str + strlen(str), ":%013.10f", tm->tm_sec + fsec); #endif TrimTrailingZeros(str); } diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 8f18b870b5..73e7bb8ea8 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.153 2005/09/09 06:46:14 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.154 2005/10/09 17:21:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -998,10 +998,8 @@ dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec) *min = time / SECS_PER_MINUTE; time -= (*min) * SECS_PER_MINUTE; *sec = time; - *fsec = JROUND(time - *sec); + *fsec = time - *sec; #endif - - return; } /* dt2time() */ @@ -1038,8 +1036,8 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, char **tzn, #endif } - time = dt; #ifdef HAVE_INT64_TIMESTAMP + time = dt; TMODULO(time, date, USECS_PER_DAY); if (time < INT64CONST(0)) @@ -1047,25 +1045,52 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, char **tzn, time += USECS_PER_DAY; date -= 1; } -#else - TMODULO(time, date, (double)SECS_PER_DAY); - - if (time < 0) - { - time += SECS_PER_DAY; - date -=1; - } -#endif /* add offset to go from J2000 back to standard Julian date */ date += POSTGRES_EPOCH_JDATE; /* Julian day routine does not work for negative Julian days */ - if (date <0 || date >(Timestamp) INT_MAX) + if (date < 0 || date > (Timestamp) INT_MAX) return -1; j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); +#else + time = dt; + TMODULO(time, date, (double)SECS_PER_DAY); + + if (time < 0) + { + time += SECS_PER_DAY; + date -= 1; + } + + /* add offset to go from J2000 back to standard Julian date */ + date += POSTGRES_EPOCH_JDATE; + +recalc_d: + /* Julian day routine does not work for negative Julian days */ + if (date < 0 || date > (Timestamp) INT_MAX) + return -1; + + j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); +recalc_t: + dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); + + *fsec = TSROUND(*fsec); + /* roundoff may need to propagate to higher-order fields */ + if (*fsec >= 1.0) + { + time = ceil(time); + if (time >= (double)SECS_PER_DAY) + { + time = 0; + date += 1; + goto recalc_d; + } + goto recalc_t; + } +#endif /* Done if no TZ conversion wanted */ if (tzp == NULL) @@ -1216,9 +1241,17 @@ interval2tm(Interval span, struct pg_tm *tm, fsec_t *fsec) tm->tm_sec = time / USECS_PER_SEC; *fsec = time - (tm->tm_sec * USECS_PER_SEC); #else +recalc: TMODULO(time, tm->tm_hour, (double)SECS_PER_HOUR); TMODULO(time, tm->tm_min, (double)SECS_PER_MINUTE); TMODULO(time, tm->tm_sec, 1.0); + time = TSROUND(time); + /* roundoff may need to propagate to higher-order fields */ + if (time >= 1.0) + { + time = ceil(span.time); + goto recalc; + } *fsec = time; #endif @@ -1237,8 +1270,7 @@ tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span) #else span->time = (((tm->tm_hour * (double)MINS_PER_HOUR) + tm->tm_min) * (double)SECS_PER_MINUTE) + - tm->tm_sec; - span->time = JROUND(span->time + fsec); + tm->tm_sec + fsec; #endif return 0; @@ -1266,7 +1298,6 @@ dt2local(Timestamp dt, int tz) dt -= (tz * USECS_PER_SEC); #else dt -= tz; - dt = JROUND(dt); #endif return dt; } /* dt2local() */ @@ -1901,11 +1932,7 @@ timestamp_mi(PG_FUNCTION_ARGS) (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("cannot subtract infinite timestamps"))); -#ifdef HAVE_INT64_TIMESTAMP result->time = dt1 - dt2; -#else - result->time = JROUND(dt1 - dt2); -#endif result->month = 0; result->day = 0; @@ -2224,11 +2251,7 @@ interval_pl(PG_FUNCTION_ARGS) result->month = span1->month + span2->month; result->day = span1->day + span2->day; -#ifdef HAVE_INT64_TIMESTAMP result->time = span1->time + span2->time; -#else - result->time = JROUND(span1->time + span2->time); -#endif PG_RETURN_INTERVAL_P(result); } @@ -2244,11 +2267,7 @@ interval_mi(PG_FUNCTION_ARGS) result->month = span1->month - span2->month; result->day = span1->day - span2->day; -#ifdef HAVE_INT64_TIMESTAMP result->time = span1->time - span2->time; -#else - result->time = JROUND(span1->time - span2->time); -#endif PG_RETURN_INTERVAL_P(result); } @@ -2280,7 +2299,7 @@ interval_mul(PG_FUNCTION_ARGS) #ifdef HAVE_INT64_TIMESTAMP result->time = rint(span->time * factor + day_remainder * USECS_PER_DAY); #else - result->time = JROUND(span->time * factor + day_remainder * SECS_PER_DAY); + result->time = span->time * factor + day_remainder * SECS_PER_DAY; #endif result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours, @@ -2332,7 +2351,6 @@ interval_div(PG_FUNCTION_ARGS) result->time += rint(day_remainder * USECS_PER_DAY); #else result->time += day_remainder * SECS_PER_DAY; - result->time = JROUND(result->time); #endif result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours, diff --git a/src/include/utils/date.h b/src/include/utils/date.h index c3c4a06d87..869e2ade29 100644 --- a/src/include/utils/date.h +++ b/src/include/utils/date.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/date.h,v 1.30 2005/02/25 16:13:29 teodor Exp $ + * $PostgreSQL: pgsql/src/include/utils/date.h,v 1.31 2005/10/09 17:21:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -60,6 +60,10 @@ typedef struct #define MAX_TIME_PRECISION 10 +/* round off to MAX_TIME_PRECISION decimal places */ +#define TIME_PREC_INV 10000000000.0 +#define TIMEROUND(j) (rint(((double) (j)) * TIME_PREC_INV) / TIME_PREC_INV) + #define DatumGetDateADT(X) ((DateADT) DatumGetInt32(X)) #define DatumGetTimeADT(X) ((TimeADT) DatumGetFloat8(X)) #define DatumGetTimeTzADTP(X) ((TimeTzADT *) DatumGetPointer(X)) diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index 14c8f6c91b..dc218f3b28 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.55 2005/10/07 20:13:16 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.56 2005/10/09 17:21:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -163,8 +163,11 @@ typedef int32 fsec_t; typedef double fsec_t; -#define TIME_PREC_INV 1000000.0 -#define JROUND(j) (rint(((double) (j)) * TIME_PREC_INV) / TIME_PREC_INV) +/* round off to MAX_TIMESTAMP_PRECISION decimal places */ +/* note: this is also used for rounding off intervals */ +#define TS_PREC_INV 1000000.0 +#define TSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV) + #endif #define TIMESTAMP_MASK(b) (1 << (b)) diff --git a/src/interfaces/ecpg/pgtypeslib/dt.h b/src/interfaces/ecpg/pgtypeslib/dt.h index 3c9dd4e018..d7ca2d5bf2 100644 --- a/src/interfaces/ecpg/pgtypeslib/dt.h +++ b/src/interfaces/ecpg/pgtypeslib/dt.h @@ -13,8 +13,11 @@ typedef int32 fsec_t; typedef double fsec_t; -#define TIME_PREC_INV 1000000.0 -#define JROUND(j) (rint(((double) (j)) * TIME_PREC_INV) / TIME_PREC_INV) +/* round off to MAX_TIMESTAMP_PRECISION decimal places */ +/* note: this is also used for rounding off intervals */ +#define TS_PREC_INV 1000000.0 +#define TSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV) + #endif #define USE_POSTGRES_DATES 0 diff --git a/src/interfaces/ecpg/pgtypeslib/dt_common.c b/src/interfaces/ecpg/pgtypeslib/dt_common.c index 7cb65f7e96..305f192a7b 100644 --- a/src/interfaces/ecpg/pgtypeslib/dt_common.c +++ b/src/interfaces/ecpg/pgtypeslib/dt_common.c @@ -1255,9 +1255,8 @@ dt2time(double jd, int *hour, int *min, int *sec, fsec_t *fsec) *min = time / SECS_PER_MINUTE; time -= (*min) * SECS_PER_MINUTE; *sec = time; - *fsec = JROUND(time - *sec); + *fsec = time - *sec; #endif - return; } /* dt2time() */ diff --git a/src/interfaces/ecpg/pgtypeslib/interval.c b/src/interfaces/ecpg/pgtypeslib/interval.c index a9ed260e70..93a9d3b45e 100644 --- a/src/interfaces/ecpg/pgtypeslib/interval.c +++ b/src/interfaces/ecpg/pgtypeslib/interval.c @@ -702,10 +702,18 @@ interval2tm(interval span, struct tm *tm, fsec_t *fsec) tm->tm_sec = time / USECS_PER_SEC; *fsec = time - (tm->tm_sec * USECS_PER_SEC); #else +recalc: TMODULO(time, tm->tm_mday, (double)SECS_PER_DAY); TMODULO(time, tm->tm_hour, (double)SECS_PER_HOUR); TMODULO(time, tm->tm_min, (double)SECS_PER_MINUTE); TMODULO(time, tm->tm_sec, 1.0); + time = TSROUND(time); + /* roundoff may need to propagate to higher-order fields */ + if (time >= 1.0) + { + time = ceil(span.time); + goto recalc; + } *fsec = time; #endif @@ -725,8 +733,7 @@ tm2interval(struct tm *tm, fsec_t fsec, interval *span) span->time = (((((tm->tm_mday * (double)HOURS_PER_DAY) + tm->tm_hour) * (double)MINS_PER_HOUR) + tm->tm_min) * (double)SECS_PER_MINUTE) + - tm->tm_sec; - span->time = JROUND(span->time + fsec); + tm->tm_sec + fsec; #endif return 0; diff --git a/src/interfaces/ecpg/pgtypeslib/timestamp.c b/src/interfaces/ecpg/pgtypeslib/timestamp.c index 74b024d0a9..5b7928b182 100644 --- a/src/interfaces/ecpg/pgtypeslib/timestamp.c +++ b/src/interfaces/ecpg/pgtypeslib/timestamp.c @@ -38,7 +38,6 @@ dt2local(timestamp dt, int tz) dt -= (tz * USECS_PER_SEC); #else dt -= tz; - dt = JROUND(dt); #endif return dt; } /* dt2local() */ @@ -124,9 +123,8 @@ dt2time(timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec) *min = time / SECS_PER_MINUTE; time -= (*min) * SECS_PER_MINUTE; *sec = time; - *fsec = JROUND(time - *sec); + *fsec = time - *sec; #endif - return; } /* dt2time() */ /* timestamp2tm() @@ -144,7 +142,7 @@ static int timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, char **tzn) { #ifdef HAVE_INT64_TIMESTAMP - int dDate, + int64 dDate, date0; int64 time; #else @@ -160,8 +158,8 @@ timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, char **tzn) date0 = date2j(2000, 1, 1); - time = dt; #ifdef HAVE_INT64_TIMESTAMP + time = dt; TMODULO(time, dDate, USECS_PER_DAY); if (time < INT64CONST(0)) @@ -169,7 +167,18 @@ timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, char **tzn) time += USECS_PER_DAY; dDate -= 1; } + + /* add offset to go from J2000 back to standard Julian date */ + dDate += date0; + + /* Julian day routine does not work for negative Julian days */ + if (dDate < 0 || dDate > (timestamp) INT_MAX) + return -1; + + j2date((int) dDate, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); #else + time = dt; TMODULO(time, dDate, (double)SECS_PER_DAY); if (time < 0) @@ -177,18 +186,34 @@ timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, char **tzn) time += SECS_PER_DAY; dDate -= 1; } -#endif - - /* Julian day routine does not work for negative Julian days */ - if (dDate < -date0) - return -1; /* add offset to go from J2000 back to standard Julian date */ dDate += date0; +recalc_d: + /* Julian day routine does not work for negative Julian days */ + if (dDate < 0 || dDate > (timestamp) INT_MAX) + return -1; + j2date((int) dDate, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); +recalc_t: dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); + *fsec = TSROUND(*fsec); + /* roundoff may need to propagate to higher-order fields */ + if (*fsec >= 1.0) + { + time = ceil(time); + if (time >= (double)SECS_PER_DAY) + { + time = 0; + dDate += 1; + goto recalc_d; + } + goto recalc_t; + } +#endif + if (tzp != NULL) { /* @@ -791,11 +816,7 @@ PGTYPEStimestamp_sub(timestamp *ts1, timestamp *ts2, interval *iv) if (TIMESTAMP_NOT_FINITE(*ts1) || TIMESTAMP_NOT_FINITE(*ts2)) return PGTYPES_TS_ERR_EINFTIME; else -#ifdef HAVE_INT64_TIMESTAMP iv->time = (ts1 - ts2); -#else - iv->time = JROUND(ts1 - ts2); -#endif iv->month = 0;