Below is the list of changes that have just been committed into a local
5.0 repository of jimw. When jimw does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet
1.2024 05/10/13 15:32:31 jimw@stripped +3 -0
Fix calculation of TIMESTAMPDIFF() of months and years. (Bug #13534)
sql/item_timefunc.cc
1.95 05/10/13 15:32:28 jimw@stripped +21 -42
Fix calculation of years and months in TIMESTAMPDIFF().
mysql-test/t/func_time.test
1.38 05/10/13 15:32:28 jimw@stripped +24 -0
Add new regression test
mysql-test/r/func_time.result
1.47 05/10/13 15:32:28 jimw@stripped +51 -0
Add new results
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: jimw
# Host: rama.(none)
# Root: /home/jimw/my/mysql-5.0-13534
--- 1.94/sql/item_timefunc.cc 2005-09-14 09:24:30 -07:00
+++ 1.95/sql/item_timefunc.cc 2005-10-13 15:32:28 -07:00
@@ -2723,16 +2723,16 @@
int_type == INTERVAL_QUARTER ||
int_type == INTERVAL_MONTH)
{
- uint year;
- uint year_beg, year_end, month_beg, month_end;
- uint diff_days= (uint) (seconds/86400L);
- uint diff_years= 0;
+ uint year_beg, year_end, month_beg, month_end, day_beg, day_end;
+ uint years= 0;
if (neg == -1)
{
year_beg= ltime2.year;
year_end= ltime1.year;
month_beg= ltime2.month;
month_end= ltime1.month;
+ day_beg= ltime2.day;
+ day_end= ltime1.day;
}
else
{
@@ -2740,53 +2740,32 @@
year_end= ltime2.year;
month_beg= ltime1.month;
month_end= ltime2.month;
- }
- /* calc years*/
- for (year= year_beg;year < year_end; year++)
- {
- uint days=calc_days_in_year(year);
- if (days > diff_days)
- break;
- diff_days-= days;
- diff_years++;
+ day_beg= ltime1.day;
+ day_end= ltime2.day;
}
- /* calc months; Current year is in the 'year' variable */
- month_beg--; /* Change months to be 0-11 for easier calculation */
- month_end--;
+ /* calc years */
+ years= year_end - year_beg;
+ if (month_end < month_beg || (month_end == month_beg && day_end <
day_beg))
+ years-= 1;
- months= 12*diff_years;
- while (month_beg != month_end)
- {
- uint m_days= (uint) days_in_month[month_beg];
- if (month_beg == 1)
- {
- /* This is only calculated once so there is no reason to cache it*/
- uint leap= (uint) ((year & 3) == 0 && (year%100 ||
- (year%400 == 0 && year)));
- m_days+= leap;
- }
- if (m_days > diff_days)
- break;
- diff_days-= m_days;
- months++;
- if (month_beg++ == 11) /* if we wrap to next year */
- {
- month_beg= 0;
- year++;
- }
- }
- if (neg == -1)
- months= -months;
+ /* calc months */
+ months= 12*years;
+ if (month_end < month_beg || (month_end == month_beg && day_end <
day_beg))
+ months+= 12 - (month_beg - month_end);
+ else
+ months+= (month_end - month_beg);
+ if (day_end < day_beg)
+ months-= 1;
}
switch (int_type) {
case INTERVAL_YEAR:
- return months/12;
+ return months/12*neg;
case INTERVAL_QUARTER:
- return months/3;
+ return months/3*neg;
case INTERVAL_MONTH:
- return months;
+ return months*neg;
case INTERVAL_WEEK:
return seconds/86400L/7L*neg;
case INTERVAL_DAY:
--- 1.46/mysql-test/r/func_time.result 2005-09-14 09:24:30 -07:00
+++ 1.47/mysql-test/r/func_time.result 2005-10-13 15:32:28 -07:00
@@ -760,3 +760,54 @@
@a != @b
1
drop procedure t_sysdate;
+select timestampdiff(month,'2004-09-11','2004-09-11');
+timestampdiff(month,'2004-09-11','2004-09-11')
+0
+select timestampdiff(month,'2004-09-11','2005-09-11');
+timestampdiff(month,'2004-09-11','2005-09-11')
+12
+select timestampdiff(month,'2004-09-11','2006-09-11');
+timestampdiff(month,'2004-09-11','2006-09-11')
+24
+select timestampdiff(month,'2004-09-11','2007-09-11');
+timestampdiff(month,'2004-09-11','2007-09-11')
+36
+select timestampdiff(month,'2005-09-11','2004-09-11');
+timestampdiff(month,'2005-09-11','2004-09-11')
+-12
+select timestampdiff(month,'2005-09-11','2003-09-11');
+timestampdiff(month,'2005-09-11','2003-09-11')
+-24
+select timestampdiff(month,'2004-02-28','2005-02-28');
+timestampdiff(month,'2004-02-28','2005-02-28')
+12
+select timestampdiff(month,'2004-02-29','2005-02-28');
+timestampdiff(month,'2004-02-29','2005-02-28')
+11
+select timestampdiff(month,'2004-02-28','2005-02-28');
+timestampdiff(month,'2004-02-28','2005-02-28')
+12
+select timestampdiff(month,'2004-03-29','2005-03-28');
+timestampdiff(month,'2004-03-29','2005-03-28')
+11
+select timestampdiff(month,'2003-02-28','2004-02-29');
+timestampdiff(month,'2003-02-28','2004-02-29')
+12
+select timestampdiff(month,'2003-02-28','2005-02-28');
+timestampdiff(month,'2003-02-28','2005-02-28')
+24
+select timestampdiff(month,'1999-09-11','2001-10-10');
+timestampdiff(month,'1999-09-11','2001-10-10')
+24
+select timestampdiff(month,'1999-09-11','2001-9-11');
+timestampdiff(month,'1999-09-11','2001-9-11')
+24
+select timestampdiff(year,'1999-09-11','2001-9-11');
+timestampdiff(year,'1999-09-11','2001-9-11')
+2
+select timestampdiff(year,'2004-02-28','2005-02-28');
+timestampdiff(year,'2004-02-28','2005-02-28')
+1
+select timestampdiff(year,'2004-02-29','2005-02-28');
+timestampdiff(year,'2004-02-29','2005-02-28')
+0
--- 1.37/mysql-test/t/func_time.test 2005-08-24 15:50:54 -07:00
+++ 1.38/mysql-test/t/func_time.test 2005-10-13 15:32:28 -07:00
@@ -404,4 +404,28 @@
call t_sysdate();
drop procedure t_sysdate;
+#
+# Bug #13534: timestampdiff() returned incorrect results across leap years
+#
+select timestampdiff(month,'2004-09-11','2004-09-11');
+select timestampdiff(month,'2004-09-11','2005-09-11');
+select timestampdiff(month,'2004-09-11','2006-09-11');
+select timestampdiff(month,'2004-09-11','2007-09-11');
+select timestampdiff(month,'2005-09-11','2004-09-11');
+select timestampdiff(month,'2005-09-11','2003-09-11');
+
+select timestampdiff(month,'2004-02-28','2005-02-28');
+select timestampdiff(month,'2004-02-29','2005-02-28');
+select timestampdiff(month,'2004-02-28','2005-02-28');
+select timestampdiff(month,'2004-03-29','2005-03-28');
+select timestampdiff(month,'2003-02-28','2004-02-29');
+select timestampdiff(month,'2003-02-28','2005-02-28');
+
+select timestampdiff(month,'1999-09-11','2001-10-10');
+select timestampdiff(month,'1999-09-11','2001-9-11');
+
+select timestampdiff(year,'1999-09-11','2001-9-11');
+select timestampdiff(year,'2004-02-28','2005-02-28');
+select timestampdiff(year,'2004-02-29','2005-02-28');
+
# End of 5.0 tests
| Thread |
|---|
| • bk commit into 5.0 tree (jimw:1.2024) BUG#13534 | Jim Winstead | 14 Oct |