From 3ec826f99a016b6cfe47db7ebbea21f46486680e Mon Sep 17 00:00:00 2001
From: "Thomas G. Lockhart" <lockhart@fourpalms.org>
Date: Tue, 4 Jan 2000 07:53:27 +0000
Subject: [PATCH] Repair two recently reported problems: 1) datetime_pl_span()
 added the seconds field before adding the months  field.  This lead to
 erroneous results for e.g.    select datetime '1999-11-30' + timespan '1 mon
 - 1 sec';  Reverse the order of operations to add months first. 2)
 tm2timespan() did all intermediate math as integer, converting to double  at
 the very end. This resulted in hidden overflows when given very large 
 integer days, hours, etc. For example,    select '74565 days'::timespan; 
 produced the wrong result. Change code to ensure that doubles are used  for
 intermediate calculations. Thanks to Olivier PRENANT <ohp@pyrenet.fr> and 
 Tulassay Zsolt <zsolt@tek.bke.hu> for problem reports and to Tom Lane for 
 accurate analyses.

---
 src/backend/utils/adt/dt.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/src/backend/utils/adt/dt.c b/src/backend/utils/adt/dt.c
index bab4873fc1f..a9ae4eebe37 100644
--- a/src/backend/utils/adt/dt.c
+++ b/src/backend/utils/adt/dt.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.79 2000/01/02 02:32:37 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.80 2000/01/04 07:53:27 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -787,6 +787,7 @@ datetime_mi(DateTime *datetime1, DateTime *datetime2)
  * To add a month, increment the month, and use the same day of month.
  * Then, if the next month has fewer days, set the day of month
  *	to the last day of month.
+ * Lastly, add in the "quantitative time".
  */
 DateTime   *
 datetime_pl_span(DateTime *datetime, TimeSpan *span)
@@ -815,12 +816,6 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span)
 	{
 		dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime);
 
-#ifdef ROUND_ALL
-		dt = JROUND(dt + span->time);
-#else
-		dt += span->time;
-#endif
-
 		if (span->month != 0)
 		{
 			struct tm	tt,
@@ -853,6 +848,12 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span)
 				DATETIME_INVALID(dt);
 		}
 
+#ifdef ROUND_ALL
+		dt = JROUND(dt + span->time);
+#else
+		dt += span->time;
+#endif
+
 		*result = dt;
 	}
 
@@ -2441,7 +2442,10 @@ static int
 tm2timespan(struct tm * tm, double fsec, TimeSpan *span)
 {
 	span->month = ((tm->tm_year * 12) + tm->tm_mon);
-	span->time = ((((((tm->tm_mday * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60) + tm->tm_sec);
+	span->time = ((((((tm->tm_mday * 24.0)
+					 + tm->tm_hour) * 60.0)
+					 + tm->tm_min) * 60.0)
+					 + tm->tm_sec);
 	span->time = JROUND(span->time + fsec);
 
 	return 0;
-- 
GitLab