summaryrefslogtreecommitdiff
path: root/sql/item_timefunc.cc
diff options
context:
space:
mode:
authorunknown <jimw@mysql.com>2005-10-13 15:32:31 -0700
committerunknown <jimw@mysql.com>2005-10-13 15:32:31 -0700
commite84f7939ecdebf760f345e61da0ea267311f0db6 (patch)
tree74b1654f734a495d34d748769708786579722b51 /sql/item_timefunc.cc
parent979446f356ce0ad3c388a2cca5dd39bad59a9243 (diff)
downloadmariadb-git-e84f7939ecdebf760f345e61da0ea267311f0db6.tar.gz
Fix calculation of TIMESTAMPDIFF() of months and years. (Bug #13534)
mysql-test/r/func_time.result: Add new results mysql-test/t/func_time.test: Add new regression test sql/item_timefunc.cc: Fix calculation of years and months in TIMESTAMPDIFF().
Diffstat (limited to 'sql/item_timefunc.cc')
-rw-r--r--sql/item_timefunc.cc63
1 files changed, 21 insertions, 42 deletions
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 7f94c19647e..459b5a22cb1 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2723,16 +2723,16 @@ longlong Item_func_timestamp_diff::val_int()
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 @@ longlong Item_func_timestamp_diff::val_int()
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: