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

Commit87de80e

Browse files
committed
I think I've finally identified the cause of the off-by-one-second
issue in timestamp conversion that we hacked around for so long byignoring the seconds field from localtime(). It's simple: you haveto watch out for platform-specific roundoff error when reducing apossibly-fractional timestamp to integral time_t form. In particularwe should subtract off the already-determined fractional fsec field.This should be enough to get an exact answer with int64 timestamps;with float timestamps, throw in a rint() call just to be sure.
1 parentd534b9e commit87de80e

File tree

1 file changed

+17
-13
lines changed

1 file changed

+17
-13
lines changed

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

Lines changed: 17 additions & 13 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.106 2004/05/21 05:08:02 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.107 2004/05/31 18:31:51 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -933,22 +933,18 @@ dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
933933
*local time zone. If out of this range, leave as GMT. - tgl 97/05/27
934934
*/
935935
int
936-
timestamp2tm(Timestampdt,int*tzp,structpg_tm*tm,fsec_t*fsec,char**tzn)
936+
timestamp2tm(Timestampdt,int*tzp,structpg_tm*tm,fsec_t*fsec,char**tzn)
937937
{
938938
#ifdefHAVE_INT64_TIMESTAMP
939-
intdate,
940-
date0;
939+
intdate;
941940
int64time;
942941
#else
943-
doubledate,
944-
date0;
942+
doubledate;
945943
doubletime;
946944
#endif
947945
time_tutime;
948946
structpg_tm*tx;
949947

950-
date0=POSTGRES_EPOCH_JDATE;
951-
952948
/*
953949
* If HasCTZSet is true then we have a brute force time zone
954950
* specified. Go ahead and rotate to the local time zone since we will
@@ -983,11 +979,11 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn
983979
#endif
984980

985981
/* Julian day routine does not work for negative Julian days */
986-
if (date<-date0)
982+
if (date<-POSTGRES_EPOCH_JDATE)
987983
return-1;
988984

989985
/* add offset to go from J2000 back to standard Julian date */
990-
date+=date0;
986+
date+=POSTGRES_EPOCH_JDATE;
991987

992988
j2date((int)date,&tm->tm_year,&tm->tm_mon,&tm->tm_mday);
993989
dt2time(time,&tm->tm_hour,&tm->tm_min,&tm->tm_sec,fsec);
@@ -1014,11 +1010,19 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn
10141010
*/
10151011
elseif (IS_VALID_UTIME(tm->tm_year,tm->tm_mon,tm->tm_mday))
10161012
{
1013+
/*
1014+
* Convert to integer, avoiding platform-specific
1015+
* roundoff-in-wrong-direction errors, and adjust to
1016+
* Unix epoch. Note we have to do this in one step
1017+
* because the intermediate result before adjustment
1018+
* won't necessarily fit in an int32.
1019+
*/
10171020
#ifdefHAVE_INT64_TIMESTAMP
1018-
utime= ((dt /INT64CONST(1000000))
1019-
+ ((date0-UNIX_EPOCH_JDATE)*INT64CONST(86400)));
1021+
utime= (dt-*fsec)/INT64CONST(1000000)+
1022+
(POSTGRES_EPOCH_JDATE-UNIX_EPOCH_JDATE)*86400;
10201023
#else
1021-
utime= (dt+ ((date0-UNIX_EPOCH_JDATE)*86400));
1024+
utime=rint(dt-*fsec+
1025+
(POSTGRES_EPOCH_JDATE-UNIX_EPOCH_JDATE)*86400);
10221026
#endif
10231027

10241028
tx=pg_localtime(&utime);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp