diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result
index 6556d2be6ad..f209866d953 100644
--- a/mysql-test/r/func_sapdb.result
+++ b/mysql-test/r/func_sapdb.result
@@ -195,6 +195,7 @@ insert into test values
 ('2001-01-01 01:01:01', '-01:01:01', '-23:59:59', "1997-12-31 23:59:59.000001"),
 ('1997-12-31 23:59:59.000001', '-23:59:59', '-01:01:01', '2001-01-01 01:01:01'),
 ('2001-01-01 01:01:01', '01:01:01', '-1 01:01:01', null),
+('2001-01-01 01:01:01', '-01:01:01', '1 01:01:01', '2001-01-01 01:01:01'),
 ('2001-01-01 01:01:01', null, '-1 01:01:01', null),
 (null, null, null, null),
 ('2001-01-01 01:01:01', '01:01:01', '1 01:01:01', '2001-01-01 01:01:01');
@@ -204,6 +205,7 @@ ttt	qqq
 2001-01-01 00:00:00	-25:01:00
 1997-12-31 00:00:00	-25:01:00
 2001-01-01 02:02:02	-24:00:00
+2001-01-01 00:00:00	24:00:00
 NULL	NULL
 NULL	NULL
 2001-01-01 02:02:02	26:02:02
@@ -213,7 +215,8 @@ ttt	qqq	eee	rrr
 -744:00:00	NULL	NULL	NULL
 26305:01:02	22:58:58	-22:58:58	NULL
 -26305:01:02	-22:58:58	22:58:58	NULL
-NULL	26:02:02	26:02:02	NULL
+NULL	26:02:02	-26:02:02	NULL
+00:00:00	-26:02:02	26:02:02	NULL
 NULL	NULL	NULL	NULL
 NULL	NULL	NULL	NULL
 00:00:00	-24:00:00	24:00:00	NULL
diff --git a/mysql-test/t/func_sapdb.test b/mysql-test/t/func_sapdb.test
index cb3ab12b5fc..bb9159eefbe 100644
--- a/mysql-test/t/func_sapdb.test
+++ b/mysql-test/t/func_sapdb.test
@@ -106,6 +106,7 @@ insert into test values
 ('2001-01-01 01:01:01', '-01:01:01', '-23:59:59', "1997-12-31 23:59:59.000001"),
 ('1997-12-31 23:59:59.000001', '-23:59:59', '-01:01:01', '2001-01-01 01:01:01'),
 ('2001-01-01 01:01:01', '01:01:01', '-1 01:01:01', null),
+('2001-01-01 01:01:01', '-01:01:01', '1 01:01:01', '2001-01-01 01:01:01'),
 ('2001-01-01 01:01:01', null, '-1 01:01:01', null),
 (null, null, null, null),
 ('2001-01-01 01:01:01', '01:01:01', '1 01:01:01', '2001-01-01 01:01:01');
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 85ba3bfd0e4..cd4777d542b 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -775,6 +775,81 @@ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
 }
 
 
+/*
+  Calculate difference between two datetime values as seconds + microseconds.
+
+  SYNOPSIS
+    calc_time_diff()
+      l_time1         - TIME/DATE/DATETIME value
+      l_time2         - TIME/DATE/DATETIME value
+      l_sign          - 1 absolute values are substracted,
+                        -1 absolute values are added.
+      seconds_out     - Out parameter where difference between
+                        l_time1 and l_time2 in seconds is stored.
+      microseconds_out- Out parameter where microsecond part of difference
+                        between l_time1 and l_time2 is stored.
+
+  NOTE
+    This function calculates difference between l_time1 and l_time2 absolute
+    values. So one should set l_sign and correct result if he want to take
+    signs into account (i.e. for TIME values).
+
+  RETURN VALUES
+    Returns sign of difference.
+    1 means negative result
+    0 means positive result
+
+*/
+
+static bool calc_time_diff(TIME *l_time1, TIME *l_time2, int l_sign,
+                           longlong *seconds_out, long *microseconds_out)
+{
+  long days;
+  bool neg;
+  longlong microseconds;
+
+  /*
+    We suppose that if first argument is MYSQL_TIMESTAMP_TIME
+    the second argument should be TIMESTAMP_TIME also.
+    We should check it before calc_time_diff call.
+  */
+  if (l_time1->time_type == MYSQL_TIMESTAMP_TIME)  // Time value
+    days= l_time1->day - l_sign*l_time2->day;
+  else
+  {
+    days= calc_daynr((uint) l_time1->year,
+		     (uint) l_time1->month,
+		     (uint) l_time1->day);
+    if (l_time2->time_type == MYSQL_TIMESTAMP_TIME)
+      days-= l_sign*l_time2->day;
+    else
+      days-= l_sign*calc_daynr((uint) l_time2->year,
+			       (uint) l_time2->month,
+			       (uint) l_time2->day);
+  }
+
+  microseconds= ((longlong)days*LL(86400) +
+                 (longlong)(l_time1->hour*3600L +
+                            l_time1->minute*60L +
+                            l_time1->second) -
+                 l_sign*(longlong)(l_time2->hour*3600L +
+                                   l_time2->minute*60L +
+                                   l_time2->second)) * LL(1000000) +
+                (longlong)l_time1->second_part -
+                l_sign*(longlong)l_time2->second_part;
+
+  neg= 0;
+  if (microseconds < 0)
+  {
+    microseconds= -microseconds;
+    neg= 1;
+  }
+  *seconds_out= microseconds/1000000L;
+  *microseconds_out= (long) (microseconds%1000000L);
+  return neg;
+}
+
+
 longlong Item_func_period_add::val_int()
 {
   DBUG_ASSERT(fixed == 1);
@@ -2373,11 +2448,11 @@ String *Item_func_add_time::val_str(String *str)
   DBUG_ASSERT(fixed == 1);
   TIME l_time1, l_time2, l_time3;
   bool is_time= 0;
-  long microseconds, seconds, days= 0;
+  long days, microseconds;
+  longlong seconds;
   int l_sign= sign;
 
   null_value=0;
-  l_time3.neg= 0;
   if (is_date)                        // TIMESTAMP function
   {
     if (get_arg0_date(&l_time1, TIME_FUZZY_DATE) || 
@@ -2393,51 +2468,26 @@ String *Item_func_add_time::val_str(String *str)
         l_time2.time_type == MYSQL_TIMESTAMP_DATETIME)
       goto null_date;
     is_time= (l_time1.time_type == MYSQL_TIMESTAMP_TIME);
-    if (is_time && (l_time2.neg == l_time1.neg && l_time1.neg))
-      l_time3.neg= 1;
   }
   if (l_time1.neg != l_time2.neg)
     l_sign= -l_sign;
 
-  microseconds= l_time1.second_part + l_sign*l_time2.second_part;
-  seconds= (l_time1.hour*3600L + l_time1.minute*60L + l_time1.second +
-	    (l_time2.day*86400L + l_time2.hour*3600L +
-	     l_time2.minute*60L + l_time2.second)*l_sign);
-  if (is_time)
-    seconds+= l_time1.day*86400L;
-  else
-    days+= calc_daynr((uint) l_time1.year,(uint) l_time1.month,
-		      (uint) l_time1.day);
-  seconds= seconds + microseconds/1000000L;
-  microseconds= microseconds%1000000L;
-  days+= seconds/86400L;
-  seconds= seconds%86400L;
+  l_time3.neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
+			      &seconds, &microseconds);
 
-  if (microseconds < 0)
-  {
-    microseconds+= 1000000L;
-    seconds--;
-  }
-  if (seconds < 0)
-  {
-    days+= seconds/86400L - 1;
-    seconds+= 86400L;
-  }
-  if (days < 0)
-  {
-    if (!is_time)
-      goto null_date;
-    if (microseconds)
-    {
-      microseconds= 1000000L - microseconds;
-      seconds++; 
-    }
-    seconds= 86400L - seconds;
-    days= -(++days);
-    l_time3.neg= 1;
-  }
+  /*
+    If first argument was negative and diff between arguments
+    is non-zero we need to swap sign to get proper result.
+  */
+  if (l_time1.neg && (seconds || microseconds))
+    l_time3.neg= 1-l_time3.neg;         // Swap sign of result
 
-  calc_time_from_sec(&l_time3, seconds, microseconds);
+  if (!is_time && l_time3.neg)
+    goto null_date;
+
+  days= (long)(seconds/86400L);
+
+  calc_time_from_sec(&l_time3, (long)(seconds%86400L), microseconds);
   if (!is_time)
   {
     get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day);
@@ -2482,71 +2532,6 @@ void Item_func_add_time::print(String *str)
 }
 
 
-/*
-  Calculate difference between two datetime values as seconds + microseconds.
-
-  SYNOPSIS
-    calc_time_diff()
-      l_time1         - TIME/DATE/DATETIME value
-      l_time2         - TIME/DATE/DATETIME value
-      l_sign          - 1 absolute values are substracted,
-                        -1 absolute values are added.
-      seconds_out     - Out parameter where difference between
-                        l_time1 and l_time2 in seconds is stored.
-      microseconds_out- Out parameter where microsecond part of difference
-                        between l_time1 and l_time2 is stored.
-
-  NOTE
-    This function calculates difference between l_time1 and l_time2 absolute
-    values. So one should set l_sign and correct result if he want to take
-    signs into account (i.e. for TIME values).
-
-  RETURN VALUES
-    Returns sign of difference.
-    1 means negative result
-    0 means positive result
-
-*/
-
-static bool calc_time_diff(TIME *l_time1, TIME *l_time2, int l_sign,
-                           longlong *seconds_out, long *microseconds_out)
-{
-  long days;
-  bool neg;
-  longlong microseconds;
-
-  /*
-    We suppose that if first argument is MYSQL_TIMESTAMP_TIME
-    the second argument should be TIMESTAMP_TIME also.
-    We should check it before calc_time_diff call.
-  */
-  if (l_time1->time_type == MYSQL_TIMESTAMP_TIME)  // Time value
-    days= l_time1->day - l_sign*l_time2->day;
-  else                                      // DateTime value
-    days= (calc_daynr((uint) l_time1->year,
-		      (uint) l_time1->month,
-		      (uint) l_time1->day) - 
-	   l_sign*calc_daynr((uint) l_time2->year,
-			     (uint) l_time2->month,
-			     (uint) l_time2->day));
-
-  microseconds= ((longlong)days*86400L +
-                 l_time1->hour*3600L + l_time1->minute*60L + l_time1->second -
-                 (longlong)l_sign*(l_time2->hour*3600L + l_time2->minute*60L +
-                                   l_time2->second))*1000000L +
-                l_time1->second_part - l_sign*l_time2->second_part;
-
-  neg= 0;
-  if (microseconds < 0)
-  {
-    microseconds= -microseconds;
-    neg= 1;
-  }
-  *seconds_out= microseconds/1000000L;
-  *microseconds_out= (long) (microseconds%1000000L);
-  return neg;
-}
-
 /*
   TIMEDIFF(t,s) is a time function that calculates the 
   time value between a start and end time.
@@ -2572,16 +2557,15 @@ String *Item_func_timediff::val_str(String *str)
   if (l_time1.neg != l_time2.neg)
     l_sign= -l_sign;
 
-  l_time3.neg= calc_time_diff(&l_time1,&l_time2, l_sign,
+  l_time3.neg= calc_time_diff(&l_time1, &l_time2, l_sign,
 			      &seconds, &microseconds);
 
   /*
     For MYSQL_TIMESTAMP_TIME only:
-      If both argumets are negative values and diff between them
+      If first argument was negative and diff between arguments
       is non-zero we need to swap sign to get proper result.
   */
-  if ((l_time2.neg == l_time1.neg) && l_time1.neg &&
-      (seconds || microseconds))
+  if (l_time1.neg && (seconds || microseconds))
     l_time3.neg= 1-l_time3.neg;         // Swap sign of result
 
   calc_time_from_sec(&l_time3, (long) seconds, microseconds);