Fix time_part and timetz_part (ie, EXTRACT() for those datatypes) to
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 29 Jul 2009 22:19:18 +0000 (22:19 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 29 Jul 2009 22:19:18 +0000 (22:19 +0000)
include a fractional part in the output for MILLISECOND and SECOND cases,
rather than truncating the source value.  This is what the float-timestamp
code has always done, and it was clearly the code author's intent to do
the same for integer timestamps, but he forgot about integer division in C.
The other datatypes supported by EXTRACT() already do this correctly.

Backpatch to 8.4, so that the default (integer) behavior of that branch will
match the default (float) behavior of older branches.  Arguably we should
patch further back, but it's possible that applications are expecting the
broken behavior in older branches.  8.4 is new enough that expectations
shouldn't be too settled.

Per report from Greg Stark.

src/backend/utils/adt/date.c

index a280ef3106e01a4b4d5bf8d1dbdc5f49d2ed3113..2085d8555e7f98804aea04d0594c0015e2e2911b 100644 (file)
@@ -1701,7 +1701,7 @@ time_part(PG_FUNCTION_ARGS)
                {
                        case DTK_MICROSEC:
 #ifdef HAVE_INT64_TIMESTAMP
-                               result = tm->tm_sec * USECS_PER_SEC + fsec;
+                               result = tm->tm_sec * 1000000.0 + fsec;
 #else
                                result = (tm->tm_sec + fsec) * 1000000;
 #endif
@@ -1709,7 +1709,7 @@ time_part(PG_FUNCTION_ARGS)
 
                        case DTK_MILLISEC:
 #ifdef HAVE_INT64_TIMESTAMP
-                               result = tm->tm_sec * INT64CONST(1000) + fsec / INT64CONST(1000);
+                               result = tm->tm_sec * 1000.0 + fsec / 1000.0;
 #else
                                result = (tm->tm_sec + fsec) * 1000;
 #endif
@@ -1717,7 +1717,7 @@ time_part(PG_FUNCTION_ARGS)
 
                        case DTK_SECOND:
 #ifdef HAVE_INT64_TIMESTAMP
-                               result = tm->tm_sec + fsec / USECS_PER_SEC;
+                               result = tm->tm_sec + fsec / 1000000.0;
 #else
                                result = tm->tm_sec + fsec;
 #endif
@@ -2469,7 +2469,7 @@ timetz_part(PG_FUNCTION_ARGS)
 
                        case DTK_MICROSEC:
 #ifdef HAVE_INT64_TIMESTAMP
-                               result = tm->tm_sec * USECS_PER_SEC + fsec;
+                               result = tm->tm_sec * 1000000.0 + fsec;
 #else
                                result = (tm->tm_sec + fsec) * 1000000;
 #endif
@@ -2477,7 +2477,7 @@ timetz_part(PG_FUNCTION_ARGS)
 
                        case DTK_MILLISEC:
 #ifdef HAVE_INT64_TIMESTAMP
-                               result = tm->tm_sec * INT64CONST(1000) + fsec / INT64CONST(1000);
+                               result = tm->tm_sec * 1000.0 + fsec / 1000.0;
 #else
                                result = (tm->tm_sec + fsec) * 1000;
 #endif
@@ -2485,7 +2485,7 @@ timetz_part(PG_FUNCTION_ARGS)
 
                        case DTK_SECOND:
 #ifdef HAVE_INT64_TIMESTAMP
-                               result = tm->tm_sec + fsec / USECS_PER_SEC;
+                               result = tm->tm_sec + fsec / 1000000.0;
 #else
                                result = tm->tm_sec + fsec;
 #endif