mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +03:00
Fix (hopefully for the last time) problems with datetime values displaying
like '23:59:60' because of fractional-second roundoff problems. Trying to control this upstream of the actual display code was hopeless; the right way is to explicitly round fractional seconds in the display code and then refigure the results if the fraction rounds up to 1. Per bug #1927.
This commit is contained in:
parent
7754f7634c
commit
313ed1ed94
@ -122,9 +122,7 @@ tstz_to_ts_gmt(Timestamp *gmt, TimestampTz *ts)
|
|||||||
*gmt -= (tz * INT64CONST(1000000));
|
*gmt -= (tz * INT64CONST(1000000));
|
||||||
#else
|
#else
|
||||||
*gmt -= tz;
|
*gmt -= tz;
|
||||||
*gmt = JROUND(*gmt);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
return gmt;
|
return gmt;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
#else
|
||||||
double trem;
|
double trem;
|
||||||
|
|
||||||
|
recalc:
|
||||||
trem = time;
|
trem = time;
|
||||||
TMODULO(trem, tm->tm_hour, (double)SECS_PER_HOUR);
|
TMODULO(trem, tm->tm_hour, (double)SECS_PER_HOUR);
|
||||||
TMODULO(trem, tm->tm_min, (double)SECS_PER_MINUTE);
|
TMODULO(trem, tm->tm_min, (double)SECS_PER_MINUTE);
|
||||||
TMODULO(trem, tm->tm_sec, 1.0);
|
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;
|
*fsec = trem;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1837,9 +1845,17 @@ timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp)
|
|||||||
#else
|
#else
|
||||||
double trem = time->time;
|
double trem = time->time;
|
||||||
|
|
||||||
|
recalc:
|
||||||
TMODULO(trem, tm->tm_hour, (double)SECS_PER_HOUR);
|
TMODULO(trem, tm->tm_hour, (double)SECS_PER_HOUR);
|
||||||
TMODULO(trem, tm->tm_min, (double)SECS_PER_MINUTE);
|
TMODULO(trem, tm->tm_min, (double)SECS_PER_MINUTE);
|
||||||
TMODULO(trem, tm->tm_sec, 1.0);
|
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;
|
*fsec = trem;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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);
|
sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print fractional seconds if any. The field widths here should be
|
* Print fractional seconds if any. The fractional field widths
|
||||||
* at least equal to the larger of MAX_TIME_PRECISION and
|
* here should be equal to the larger of MAX_TIME_PRECISION and
|
||||||
* MAX_TIMESTAMP_PRECISION.
|
* MAX_TIMESTAMP_PRECISION.
|
||||||
*/
|
*/
|
||||||
if (fsec != 0)
|
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
|
#ifdef HAVE_INT64_TIMESTAMP
|
||||||
sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
|
sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
|
||||||
#else
|
#else
|
||||||
sprintf(str + strlen(str), ":%012.9f", tm->tm_sec + fsec);
|
sprintf(str + strlen(str), ":%013.10f", tm->tm_sec + fsec);
|
||||||
#endif
|
#endif
|
||||||
TrimTrailingZeros(str);
|
TrimTrailingZeros(str);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
*min = time / SECS_PER_MINUTE;
|
||||||
time -= (*min) * SECS_PER_MINUTE;
|
time -= (*min) * SECS_PER_MINUTE;
|
||||||
*sec = time;
|
*sec = time;
|
||||||
*fsec = JROUND(time - *sec);
|
*fsec = time - *sec;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return;
|
|
||||||
} /* dt2time() */
|
} /* dt2time() */
|
||||||
|
|
||||||
|
|
||||||
@ -1038,8 +1036,8 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, char **tzn,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
time = dt;
|
|
||||||
#ifdef HAVE_INT64_TIMESTAMP
|
#ifdef HAVE_INT64_TIMESTAMP
|
||||||
|
time = dt;
|
||||||
TMODULO(time, date, USECS_PER_DAY);
|
TMODULO(time, date, USECS_PER_DAY);
|
||||||
|
|
||||||
if (time < INT64CONST(0))
|
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;
|
time += USECS_PER_DAY;
|
||||||
date -= 1;
|
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 */
|
/* add offset to go from J2000 back to standard Julian date */
|
||||||
date += POSTGRES_EPOCH_JDATE;
|
date += POSTGRES_EPOCH_JDATE;
|
||||||
|
|
||||||
/* Julian day routine does not work for negative Julian days */
|
/* 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;
|
return -1;
|
||||||
|
|
||||||
j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
|
j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
|
||||||
dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
|
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 */
|
/* Done if no TZ conversion wanted */
|
||||||
if (tzp == NULL)
|
if (tzp == NULL)
|
||||||
@ -1216,9 +1241,17 @@ interval2tm(Interval span, struct pg_tm *tm, fsec_t *fsec)
|
|||||||
tm->tm_sec = time / USECS_PER_SEC;
|
tm->tm_sec = time / USECS_PER_SEC;
|
||||||
*fsec = time - (tm->tm_sec * USECS_PER_SEC);
|
*fsec = time - (tm->tm_sec * USECS_PER_SEC);
|
||||||
#else
|
#else
|
||||||
|
recalc:
|
||||||
TMODULO(time, tm->tm_hour, (double)SECS_PER_HOUR);
|
TMODULO(time, tm->tm_hour, (double)SECS_PER_HOUR);
|
||||||
TMODULO(time, tm->tm_min, (double)SECS_PER_MINUTE);
|
TMODULO(time, tm->tm_min, (double)SECS_PER_MINUTE);
|
||||||
TMODULO(time, tm->tm_sec, 1.0);
|
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;
|
*fsec = time;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1237,8 +1270,7 @@ tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span)
|
|||||||
#else
|
#else
|
||||||
span->time = (((tm->tm_hour * (double)MINS_PER_HOUR) +
|
span->time = (((tm->tm_hour * (double)MINS_PER_HOUR) +
|
||||||
tm->tm_min) * (double)SECS_PER_MINUTE) +
|
tm->tm_min) * (double)SECS_PER_MINUTE) +
|
||||||
tm->tm_sec;
|
tm->tm_sec + fsec;
|
||||||
span->time = JROUND(span->time + fsec);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1266,7 +1298,6 @@ dt2local(Timestamp dt, int tz)
|
|||||||
dt -= (tz * USECS_PER_SEC);
|
dt -= (tz * USECS_PER_SEC);
|
||||||
#else
|
#else
|
||||||
dt -= tz;
|
dt -= tz;
|
||||||
dt = JROUND(dt);
|
|
||||||
#endif
|
#endif
|
||||||
return dt;
|
return dt;
|
||||||
} /* dt2local() */
|
} /* dt2local() */
|
||||||
@ -1901,11 +1932,7 @@ timestamp_mi(PG_FUNCTION_ARGS)
|
|||||||
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("cannot subtract infinite timestamps")));
|
errmsg("cannot subtract infinite timestamps")));
|
||||||
|
|
||||||
#ifdef HAVE_INT64_TIMESTAMP
|
|
||||||
result->time = dt1 - dt2;
|
result->time = dt1 - dt2;
|
||||||
#else
|
|
||||||
result->time = JROUND(dt1 - dt2);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
result->month = 0;
|
result->month = 0;
|
||||||
result->day = 0;
|
result->day = 0;
|
||||||
@ -2224,11 +2251,7 @@ interval_pl(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
result->month = span1->month + span2->month;
|
result->month = span1->month + span2->month;
|
||||||
result->day = span1->day + span2->day;
|
result->day = span1->day + span2->day;
|
||||||
#ifdef HAVE_INT64_TIMESTAMP
|
|
||||||
result->time = span1->time + span2->time;
|
result->time = span1->time + span2->time;
|
||||||
#else
|
|
||||||
result->time = JROUND(span1->time + span2->time);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PG_RETURN_INTERVAL_P(result);
|
PG_RETURN_INTERVAL_P(result);
|
||||||
}
|
}
|
||||||
@ -2244,11 +2267,7 @@ interval_mi(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
result->month = span1->month - span2->month;
|
result->month = span1->month - span2->month;
|
||||||
result->day = span1->day - span2->day;
|
result->day = span1->day - span2->day;
|
||||||
#ifdef HAVE_INT64_TIMESTAMP
|
|
||||||
result->time = span1->time - span2->time;
|
result->time = span1->time - span2->time;
|
||||||
#else
|
|
||||||
result->time = JROUND(span1->time - span2->time);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PG_RETURN_INTERVAL_P(result);
|
PG_RETURN_INTERVAL_P(result);
|
||||||
}
|
}
|
||||||
@ -2280,7 +2299,7 @@ interval_mul(PG_FUNCTION_ARGS)
|
|||||||
#ifdef HAVE_INT64_TIMESTAMP
|
#ifdef HAVE_INT64_TIMESTAMP
|
||||||
result->time = rint(span->time * factor + day_remainder * USECS_PER_DAY);
|
result->time = rint(span->time * factor + day_remainder * USECS_PER_DAY);
|
||||||
#else
|
#else
|
||||||
result->time = JROUND(span->time * factor + day_remainder * SECS_PER_DAY);
|
result->time = span->time * factor + day_remainder * SECS_PER_DAY;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
|
result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
|
||||||
@ -2332,7 +2351,6 @@ interval_div(PG_FUNCTION_ARGS)
|
|||||||
result->time += rint(day_remainder * USECS_PER_DAY);
|
result->time += rint(day_remainder * USECS_PER_DAY);
|
||||||
#else
|
#else
|
||||||
result->time += day_remainder * SECS_PER_DAY;
|
result->time += day_remainder * SECS_PER_DAY;
|
||||||
result->time = JROUND(result->time);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
|
result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#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 DatumGetDateADT(X) ((DateADT) DatumGetInt32(X))
|
||||||
#define DatumGetTimeADT(X) ((TimeADT) DatumGetFloat8(X))
|
#define DatumGetTimeADT(X) ((TimeADT) DatumGetFloat8(X))
|
||||||
#define DatumGetTimeTzADTP(X) ((TimeTzADT *) DatumGetPointer(X))
|
#define DatumGetTimeTzADTP(X) ((TimeTzADT *) DatumGetPointer(X))
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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;
|
typedef double fsec_t;
|
||||||
|
|
||||||
#define TIME_PREC_INV 1000000.0
|
/* round off to MAX_TIMESTAMP_PRECISION decimal places */
|
||||||
#define JROUND(j) (rint(((double) (j)) * TIME_PREC_INV) / TIME_PREC_INV)
|
/* 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
|
#endif
|
||||||
|
|
||||||
#define TIMESTAMP_MASK(b) (1 << (b))
|
#define TIMESTAMP_MASK(b) (1 << (b))
|
||||||
|
@ -13,8 +13,11 @@ typedef int32 fsec_t;
|
|||||||
|
|
||||||
typedef double fsec_t;
|
typedef double fsec_t;
|
||||||
|
|
||||||
#define TIME_PREC_INV 1000000.0
|
/* round off to MAX_TIMESTAMP_PRECISION decimal places */
|
||||||
#define JROUND(j) (rint(((double) (j)) * TIME_PREC_INV) / TIME_PREC_INV)
|
/* 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
|
#endif
|
||||||
|
|
||||||
#define USE_POSTGRES_DATES 0
|
#define USE_POSTGRES_DATES 0
|
||||||
|
@ -1255,9 +1255,8 @@ dt2time(double jd, int *hour, int *min, int *sec, fsec_t *fsec)
|
|||||||
*min = time / SECS_PER_MINUTE;
|
*min = time / SECS_PER_MINUTE;
|
||||||
time -= (*min) * SECS_PER_MINUTE;
|
time -= (*min) * SECS_PER_MINUTE;
|
||||||
*sec = time;
|
*sec = time;
|
||||||
*fsec = JROUND(time - *sec);
|
*fsec = time - *sec;
|
||||||
#endif
|
#endif
|
||||||
return;
|
|
||||||
} /* dt2time() */
|
} /* dt2time() */
|
||||||
|
|
||||||
|
|
||||||
|
@ -702,10 +702,18 @@ interval2tm(interval span, struct tm *tm, fsec_t *fsec)
|
|||||||
tm->tm_sec = time / USECS_PER_SEC;
|
tm->tm_sec = time / USECS_PER_SEC;
|
||||||
*fsec = time - (tm->tm_sec * USECS_PER_SEC);
|
*fsec = time - (tm->tm_sec * USECS_PER_SEC);
|
||||||
#else
|
#else
|
||||||
|
recalc:
|
||||||
TMODULO(time, tm->tm_mday, (double)SECS_PER_DAY);
|
TMODULO(time, tm->tm_mday, (double)SECS_PER_DAY);
|
||||||
TMODULO(time, tm->tm_hour, (double)SECS_PER_HOUR);
|
TMODULO(time, tm->tm_hour, (double)SECS_PER_HOUR);
|
||||||
TMODULO(time, tm->tm_min, (double)SECS_PER_MINUTE);
|
TMODULO(time, tm->tm_min, (double)SECS_PER_MINUTE);
|
||||||
TMODULO(time, tm->tm_sec, 1.0);
|
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;
|
*fsec = time;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -725,8 +733,7 @@ tm2interval(struct tm *tm, fsec_t fsec, interval *span)
|
|||||||
span->time = (((((tm->tm_mday * (double)HOURS_PER_DAY) +
|
span->time = (((((tm->tm_mday * (double)HOURS_PER_DAY) +
|
||||||
tm->tm_hour) * (double)MINS_PER_HOUR) +
|
tm->tm_hour) * (double)MINS_PER_HOUR) +
|
||||||
tm->tm_min) * (double)SECS_PER_MINUTE) +
|
tm->tm_min) * (double)SECS_PER_MINUTE) +
|
||||||
tm->tm_sec;
|
tm->tm_sec + fsec;
|
||||||
span->time = JROUND(span->time + fsec);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -38,7 +38,6 @@ dt2local(timestamp dt, int tz)
|
|||||||
dt -= (tz * USECS_PER_SEC);
|
dt -= (tz * USECS_PER_SEC);
|
||||||
#else
|
#else
|
||||||
dt -= tz;
|
dt -= tz;
|
||||||
dt = JROUND(dt);
|
|
||||||
#endif
|
#endif
|
||||||
return dt;
|
return dt;
|
||||||
} /* dt2local() */
|
} /* dt2local() */
|
||||||
@ -124,9 +123,8 @@ dt2time(timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
|
|||||||
*min = time / SECS_PER_MINUTE;
|
*min = time / SECS_PER_MINUTE;
|
||||||
time -= (*min) * SECS_PER_MINUTE;
|
time -= (*min) * SECS_PER_MINUTE;
|
||||||
*sec = time;
|
*sec = time;
|
||||||
*fsec = JROUND(time - *sec);
|
*fsec = time - *sec;
|
||||||
#endif
|
#endif
|
||||||
return;
|
|
||||||
} /* dt2time() */
|
} /* dt2time() */
|
||||||
|
|
||||||
/* timestamp2tm()
|
/* timestamp2tm()
|
||||||
@ -144,7 +142,7 @@ static int
|
|||||||
timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, char **tzn)
|
timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, char **tzn)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_INT64_TIMESTAMP
|
#ifdef HAVE_INT64_TIMESTAMP
|
||||||
int dDate,
|
int64 dDate,
|
||||||
date0;
|
date0;
|
||||||
int64 time;
|
int64 time;
|
||||||
#else
|
#else
|
||||||
@ -160,8 +158,8 @@ timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, char **tzn)
|
|||||||
|
|
||||||
date0 = date2j(2000, 1, 1);
|
date0 = date2j(2000, 1, 1);
|
||||||
|
|
||||||
time = dt;
|
|
||||||
#ifdef HAVE_INT64_TIMESTAMP
|
#ifdef HAVE_INT64_TIMESTAMP
|
||||||
|
time = dt;
|
||||||
TMODULO(time, dDate, USECS_PER_DAY);
|
TMODULO(time, dDate, USECS_PER_DAY);
|
||||||
|
|
||||||
if (time < INT64CONST(0))
|
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;
|
time += USECS_PER_DAY;
|
||||||
dDate -= 1;
|
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
|
#else
|
||||||
|
time = dt;
|
||||||
TMODULO(time, dDate, (double)SECS_PER_DAY);
|
TMODULO(time, dDate, (double)SECS_PER_DAY);
|
||||||
|
|
||||||
if (time < 0)
|
if (time < 0)
|
||||||
@ -177,18 +186,34 @@ timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, char **tzn)
|
|||||||
time += SECS_PER_DAY;
|
time += SECS_PER_DAY;
|
||||||
dDate -= 1;
|
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 */
|
/* add offset to go from J2000 back to standard Julian date */
|
||||||
dDate += date0;
|
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);
|
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);
|
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)
|
if (tzp != NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -791,11 +816,7 @@ PGTYPEStimestamp_sub(timestamp *ts1, timestamp *ts2, interval *iv)
|
|||||||
if (TIMESTAMP_NOT_FINITE(*ts1) || TIMESTAMP_NOT_FINITE(*ts2))
|
if (TIMESTAMP_NOT_FINITE(*ts1) || TIMESTAMP_NOT_FINITE(*ts2))
|
||||||
return PGTYPES_TS_ERR_EINFTIME;
|
return PGTYPES_TS_ERR_EINFTIME;
|
||||||
else
|
else
|
||||||
#ifdef HAVE_INT64_TIMESTAMP
|
|
||||||
iv->time = (ts1 - ts2);
|
iv->time = (ts1 - ts2);
|
||||||
#else
|
|
||||||
iv->time = JROUND(ts1 - ts2);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
iv->month = 0;
|
iv->month = 0;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user