Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit313ed1e

Browse files
committed
Fix (hopefully for the last time) problems with datetime values displaying
like '23:59:60' because of fractional-second roundoff problems. Tryingto control this upstream of the actual display code was hopeless; the rightway is to explicitly round fractional seconds in the display code and thenrefigure the results if the fraction rounds up to 1. Per bug #1927.
1 parent7754f76 commit313ed1e

File tree

10 files changed

+125
-56
lines changed

10 files changed

+125
-56
lines changed

‎contrib/btree_gist/btree_ts.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,7 @@ tstz_to_ts_gmt(Timestamp *gmt, TimestampTz *ts)
122122
*gmt-= (tz*INT64CONST(1000000));
123123
#else
124124
*gmt-=tz;
125-
*gmt=JROUND(*gmt);
126125
#endif
127-
128126
}
129127
returngmt;
130128
}

‎src/backend/utils/adt/date.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.120 2005/09/0902:31:49 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.121 2005/10/0917:21:46 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -944,10 +944,18 @@ time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec)
944944
#else
945945
doubletrem;
946946

947+
recalc:
947948
trem=time;
948949
TMODULO(trem,tm->tm_hour, (double)SECS_PER_HOUR);
949950
TMODULO(trem,tm->tm_min, (double)SECS_PER_MINUTE);
950951
TMODULO(trem,tm->tm_sec,1.0);
952+
trem=TIMEROUND(trem);
953+
/* roundoff may need to propagate to higher-order fields */
954+
if (trem >=1.0)
955+
{
956+
time=ceil(time);
957+
gotorecalc;
958+
}
951959
*fsec=trem;
952960
#endif
953961

@@ -1837,9 +1845,17 @@ timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp)
18371845
#else
18381846
doubletrem=time->time;
18391847

1848+
recalc:
18401849
TMODULO(trem,tm->tm_hour, (double)SECS_PER_HOUR);
18411850
TMODULO(trem,tm->tm_min, (double)SECS_PER_MINUTE);
18421851
TMODULO(trem,tm->tm_sec,1.0);
1852+
trem=TIMEROUND(trem);
1853+
/* roundoff may need to propagate to higher-order fields */
1854+
if (trem >=1.0)
1855+
{
1856+
trem=ceil(time->time);
1857+
gotorecalc;
1858+
}
18431859
*fsec=trem;
18441860
#endif
18451861

‎src/backend/utils/adt/datetime.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.157 2005/07/23 14:25:33 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.158 2005/10/09 17:21:46 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -3488,16 +3488,16 @@ EncodeTimeOnly(struct pg_tm *tm, fsec_t fsec, int *tzp, int style, char *str)
34883488
sprintf(str,"%02d:%02d",tm->tm_hour,tm->tm_min);
34893489

34903490
/*
3491-
* Print fractional seconds if any. The field widths here should be
3492-
*at least equal to the larger of MAX_TIME_PRECISION and
3491+
* Print fractional seconds if any. Thefractionalfield widths
3492+
*here should be equal to the larger of MAX_TIME_PRECISION and
34933493
* MAX_TIMESTAMP_PRECISION.
34943494
*/
34953495
if (fsec!=0)
34963496
{
34973497
#ifdefHAVE_INT64_TIMESTAMP
34983498
sprintf(str+strlen(str),":%02d.%06d",tm->tm_sec,fsec);
34993499
#else
3500-
sprintf(str+strlen(str),":%012.9f",tm->tm_sec+fsec);
3500+
sprintf(str+strlen(str),":%013.10f",tm->tm_sec+fsec);
35013501
#endif
35023502
TrimTrailingZeros(str);
35033503
}

‎src/backend/utils/adt/timestamp.c

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.153 2005/09/0906:46:14 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.154 2005/10/0917:21:46 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -998,10 +998,8 @@ dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
998998
*min=time /SECS_PER_MINUTE;
999999
time-= (*min)*SECS_PER_MINUTE;
10001000
*sec=time;
1001-
*fsec=JROUND(time-*sec);
1001+
*fsec=time-*sec;
10021002
#endif
1003-
1004-
return;
10051003
}/* dt2time() */
10061004

10071005

@@ -1038,35 +1036,62 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, char **tzn,
10381036
#endif
10391037
}
10401038

1041-
time=dt;
10421039
#ifdefHAVE_INT64_TIMESTAMP
1040+
time=dt;
10431041
TMODULO(time,date,USECS_PER_DAY);
10441042

10451043
if (time<INT64CONST(0))
10461044
{
10471045
time+=USECS_PER_DAY;
10481046
date-=1;
10491047
}
1048+
1049+
/* add offset to go from J2000 back to standard Julian date */
1050+
date+=POSTGRES_EPOCH_JDATE;
1051+
1052+
/* Julian day routine does not work for negative Julian days */
1053+
if (date<0||date> (Timestamp)INT_MAX)
1054+
return-1;
1055+
1056+
j2date((int)date,&tm->tm_year,&tm->tm_mon,&tm->tm_mday);
1057+
dt2time(time,&tm->tm_hour,&tm->tm_min,&tm->tm_sec,fsec);
10501058
#else
1059+
time=dt;
10511060
TMODULO(time,date, (double)SECS_PER_DAY);
10521061

10531062
if (time<0)
10541063
{
10551064
time+=SECS_PER_DAY;
1056-
date-=1;
1065+
date-=1;
10571066
}
1058-
#endif
10591067

10601068
/* add offset to go from J2000 back to standard Julian date */
10611069
date+=POSTGRES_EPOCH_JDATE;
10621070

1071+
recalc_d:
10631072
/* Julian day routine does not work for negative Julian days */
1064-
if (date<0||date>(Timestamp)INT_MAX)
1073+
if (date<0||date>(Timestamp)INT_MAX)
10651074
return-1;
10661075

10671076
j2date((int)date,&tm->tm_year,&tm->tm_mon,&tm->tm_mday);
1077+
recalc_t:
10681078
dt2time(time,&tm->tm_hour,&tm->tm_min,&tm->tm_sec,fsec);
10691079

1080+
*fsec=TSROUND(*fsec);
1081+
/* roundoff may need to propagate to higher-order fields */
1082+
if (*fsec >=1.0)
1083+
{
1084+
time=ceil(time);
1085+
if (time >= (double)SECS_PER_DAY)
1086+
{
1087+
time=0;
1088+
date+=1;
1089+
gotorecalc_d;
1090+
}
1091+
gotorecalc_t;
1092+
}
1093+
#endif
1094+
10701095
/* Done if no TZ conversion wanted */
10711096
if (tzp==NULL)
10721097
{
@@ -1216,9 +1241,17 @@ interval2tm(Interval span, struct pg_tm *tm, fsec_t *fsec)
12161241
tm->tm_sec=time /USECS_PER_SEC;
12171242
*fsec=time- (tm->tm_sec*USECS_PER_SEC);
12181243
#else
1244+
recalc:
12191245
TMODULO(time,tm->tm_hour, (double)SECS_PER_HOUR);
12201246
TMODULO(time,tm->tm_min, (double)SECS_PER_MINUTE);
12211247
TMODULO(time,tm->tm_sec,1.0);
1248+
time=TSROUND(time);
1249+
/* roundoff may need to propagate to higher-order fields */
1250+
if (time >=1.0)
1251+
{
1252+
time=ceil(span.time);
1253+
gotorecalc;
1254+
}
12221255
*fsec=time;
12231256
#endif
12241257

@@ -1237,8 +1270,7 @@ tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span)
12371270
#else
12381271
span->time= (((tm->tm_hour* (double)MINS_PER_HOUR)+
12391272
tm->tm_min)* (double)SECS_PER_MINUTE)+
1240-
tm->tm_sec;
1241-
span->time=JROUND(span->time+fsec);
1273+
tm->tm_sec+fsec;
12421274
#endif
12431275

12441276
return0;
@@ -1266,7 +1298,6 @@ dt2local(Timestamp dt, int tz)
12661298
dt-= (tz*USECS_PER_SEC);
12671299
#else
12681300
dt-=tz;
1269-
dt=JROUND(dt);
12701301
#endif
12711302
returndt;
12721303
}/* dt2local() */
@@ -1901,11 +1932,7 @@ timestamp_mi(PG_FUNCTION_ARGS)
19011932
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
19021933
errmsg("cannot subtract infinite timestamps")));
19031934

1904-
#ifdefHAVE_INT64_TIMESTAMP
19051935
result->time=dt1-dt2;
1906-
#else
1907-
result->time=JROUND(dt1-dt2);
1908-
#endif
19091936

19101937
result->month=0;
19111938
result->day=0;
@@ -2224,11 +2251,7 @@ interval_pl(PG_FUNCTION_ARGS)
22242251

22252252
result->month=span1->month+span2->month;
22262253
result->day=span1->day+span2->day;
2227-
#ifdefHAVE_INT64_TIMESTAMP
22282254
result->time=span1->time+span2->time;
2229-
#else
2230-
result->time=JROUND(span1->time+span2->time);
2231-
#endif
22322255

22332256
PG_RETURN_INTERVAL_P(result);
22342257
}
@@ -2244,11 +2267,7 @@ interval_mi(PG_FUNCTION_ARGS)
22442267

22452268
result->month=span1->month-span2->month;
22462269
result->day=span1->day-span2->day;
2247-
#ifdefHAVE_INT64_TIMESTAMP
22482270
result->time=span1->time-span2->time;
2249-
#else
2250-
result->time=JROUND(span1->time-span2->time);
2251-
#endif
22522271

22532272
PG_RETURN_INTERVAL_P(result);
22542273
}
@@ -2280,7 +2299,7 @@ interval_mul(PG_FUNCTION_ARGS)
22802299
#ifdefHAVE_INT64_TIMESTAMP
22812300
result->time=rint(span->time*factor+day_remainder*USECS_PER_DAY);
22822301
#else
2283-
result->time=JROUND(span->time*factor+day_remainder*SECS_PER_DAY);
2302+
result->time=span->time*factor+day_remainder*SECS_PER_DAY;
22842303
#endif
22852304

22862305
result=DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
@@ -2332,7 +2351,6 @@ interval_div(PG_FUNCTION_ARGS)
23322351
result->time+=rint(day_remainder*USECS_PER_DAY);
23332352
#else
23342353
result->time+=day_remainder*SECS_PER_DAY;
2335-
result->time=JROUND(result->time);
23362354
#endif
23372355

23382356
result=DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,

‎src/include/utils/date.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/utils/date.h,v 1.30 2005/02/25 16:13:29 teodor Exp $
10+
* $PostgreSQL: pgsql/src/include/utils/date.h,v 1.31 2005/10/09 17:21:47 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -60,6 +60,10 @@ typedef struct
6060

6161
#defineMAX_TIME_PRECISION 10
6262

63+
/* round off to MAX_TIME_PRECISION decimal places */
64+
#defineTIME_PREC_INV 10000000000.0
65+
#defineTIMEROUND(j) (rint(((double) (j)) * TIME_PREC_INV) / TIME_PREC_INV)
66+
6367
#defineDatumGetDateADT(X) ((DateADT) DatumGetInt32(X))
6468
#defineDatumGetTimeADT(X) ((TimeADT) DatumGetFloat8(X))
6569
#defineDatumGetTimeTzADTP(X) ((TimeTzADT *) DatumGetPointer(X))

‎src/include/utils/timestamp.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.55 2005/10/07 20:13:16 momjian Exp $
9+
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.56 2005/10/09 17:21:47 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -163,8 +163,11 @@ typedef int32 fsec_t;
163163

164164
typedefdoublefsec_t;
165165

166-
#defineTIME_PREC_INV 1000000.0
167-
#defineJROUND(j) (rint(((double) (j)) * TIME_PREC_INV) / TIME_PREC_INV)
166+
/* round off to MAX_TIMESTAMP_PRECISION decimal places */
167+
/* note: this is also used for rounding off intervals */
168+
#defineTS_PREC_INV 1000000.0
169+
#defineTSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV)
170+
168171
#endif
169172

170173
#defineTIMESTAMP_MASK(b) (1 << (b))

‎src/interfaces/ecpg/pgtypeslib/dt.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ typedef int32 fsec_t;
1313

1414
typedefdoublefsec_t;
1515

16-
#defineTIME_PREC_INV 1000000.0
17-
#defineJROUND(j) (rint(((double) (j)) * TIME_PREC_INV) / TIME_PREC_INV)
16+
/* round off to MAX_TIMESTAMP_PRECISION decimal places */
17+
/* note: this is also used for rounding off intervals */
18+
#defineTS_PREC_INV 1000000.0
19+
#defineTSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV)
20+
1821
#endif
1922

2023
#defineUSE_POSTGRES_DATES0

‎src/interfaces/ecpg/pgtypeslib/dt_common.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,9 +1255,8 @@ dt2time(double jd, int *hour, int *min, int *sec, fsec_t *fsec)
12551255
*min=time /SECS_PER_MINUTE;
12561256
time-= (*min)*SECS_PER_MINUTE;
12571257
*sec=time;
1258-
*fsec=JROUND(time-*sec);
1258+
*fsec=time-*sec;
12591259
#endif
1260-
return;
12611260
}/* dt2time() */
12621261

12631262

‎src/interfaces/ecpg/pgtypeslib/interval.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -702,10 +702,18 @@ interval2tm(interval span, struct tm *tm, fsec_t *fsec)
702702
tm->tm_sec=time /USECS_PER_SEC;
703703
*fsec=time- (tm->tm_sec*USECS_PER_SEC);
704704
#else
705+
recalc:
705706
TMODULO(time,tm->tm_mday, (double)SECS_PER_DAY);
706707
TMODULO(time,tm->tm_hour, (double)SECS_PER_HOUR);
707708
TMODULO(time,tm->tm_min, (double)SECS_PER_MINUTE);
708709
TMODULO(time,tm->tm_sec,1.0);
710+
time=TSROUND(time);
711+
/* roundoff may need to propagate to higher-order fields */
712+
if (time >=1.0)
713+
{
714+
time=ceil(span.time);
715+
gotorecalc;
716+
}
709717
*fsec=time;
710718
#endif
711719

@@ -725,8 +733,7 @@ tm2interval(struct tm *tm, fsec_t fsec, interval *span)
725733
span->time= (((((tm->tm_mday* (double)HOURS_PER_DAY)+
726734
tm->tm_hour)* (double)MINS_PER_HOUR)+
727735
tm->tm_min)* (double)SECS_PER_MINUTE)+
728-
tm->tm_sec;
729-
span->time=JROUND(span->time+fsec);
736+
tm->tm_sec+fsec;
730737
#endif
731738

732739
return0;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp