Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-14731

EXTRACT(HOUR ....) gives incorect value when hour > 23

Details

    • Bug
    • Status: Closed (View Workflow)
    • Minor
    • Resolution: Not a Bug
    • 5.5(EOL), 10.0(EOL), 10.1(EOL), 10.2(EOL)
    • N/A
    • Temporal Types
    • None

    Description

      Using extract to get number of hours from a time_diff function produces incorrect results when number of hours is greater than 23.

      Here's the details...

      SET @prev_ts = '2017-11-30 11:00:00';
      SELECT NOW()
          , TIMEDIFF(NOW(),@prev_ts)
          , TIME_FORMAT(TIMEDIFF(NOW(),@prev_ts), '%H') AS 'diff TIME_FORMAT'
          , EXTRACT(HOUR FROM  TIMEDIFF(NOW(),@prev_ts)) AS 'diff EXTRACT '
      ;
      /*
      NOW()                          TIMEDIFF(NOW(),@prev_ts)  diff TIME_FORMAT  diff EXTRACT   
      2017-12-15 20:58:25   369:58:25                                369               9              
      */
      

      SET @prev_ts = '2017-12-14 22:00:00';
      SELECT NOW()
          , TIMEDIFF(NOW(),@prev_ts)
          , TIME_FORMAT(TIMEDIFF(NOW(),@prev_ts), '%H') AS 'diff TIME_FORMAT'
          , EXTRACT(HOUR FROM  TIMEDIFF(NOW(),@prev_ts)) AS 'diff EXTRACT '
      ;
      /*
      NOW()                          TIMEDIFF(NOW(),@prev_ts)  diff TIME_FORMAT  diff EXTRACT   
      2017-12-15 21:19:32   23:19:32                                  23                             23             
      */
      

      Attachments

        Activity

          I think this is working as designed. Extract (hour from ..) is meant to be hour of day not total hours. This behaves the same in both columnstore and regular mariadb 10.2. Is your goal to calculate the total number of hours between the 2 dates, if so i think the following is what you need:
          select timestampdiff(hour, @prev_ts, now());

          dthompson David Thompson (Inactive) added a comment - I think this is working as designed. Extract (hour from ..) is meant to be hour of day not total hours. This behaves the same in both columnstore and regular mariadb 10.2. Is your goal to calculate the total number of hours between the 2 dates, if so i think the following is what you need: select timestampdiff(hour, @prev_ts, now());

          Thanks David,

          I came across this issue doing some testing. We are looking at moving an app from MySQL to MariaDB column store. As you pointed out there are many ways to solve the problem. I thought it was a bug because it behaves differently on our MySQL servers running 5.1.53, 5.6.23 and 5.7.17. They all return the total hours...

          SET @prev_ts = '2017-11-30 11:00:00';
          SELECT NOW()
          , TIMEDIFF(NOW(),@prev_ts)
          , TIME_FORMAT(TIMEDIFF(NOW(),@prev_ts), '%H') AS 'diff TIME_FORMAT'
          , EXTRACT(HOUR FROM TIMEDIFF(NOW(),@prev_ts)) AS 'diff EXTRACT '
          ;
          /*
          NOW() TIMEDIFF(NOW(),@prev_ts) diff TIME_FORMAT diff EXTRACT
          2017-12-19 16:09:14 461:09:14 461 461
          */

          This is not going to be a problem for me, but I thought i should report it.

          thebreadguru MIke Thibodeau added a comment - Thanks David, I came across this issue doing some testing. We are looking at moving an app from MySQL to MariaDB column store. As you pointed out there are many ways to solve the problem. I thought it was a bug because it behaves differently on our MySQL servers running 5.1.53, 5.6.23 and 5.7.17. They all return the total hours... SET @prev_ts = '2017-11-30 11:00:00'; SELECT NOW() , TIMEDIFF(NOW(),@prev_ts) , TIME_FORMAT(TIMEDIFF(NOW(),@prev_ts), '%H') AS 'diff TIME_FORMAT' , EXTRACT(HOUR FROM TIMEDIFF(NOW(),@prev_ts)) AS 'diff EXTRACT ' ; /* NOW() TIMEDIFF(NOW(),@prev_ts) diff TIME_FORMAT diff EXTRACT 2017-12-19 16:09:14 461:09:14 461 461 */ This is not going to be a problem for me, but I thought i should report it.

          I see what you mean. This actually seems to be more of a general behavior difference between mysql and mariadb so i'm moving it over to the core server component for their review as i'm not sure if this is intentional behavior difference or not.

          dthompson David Thompson (Inactive) added a comment - I see what you mean. This actually seems to be more of a general behavior difference between mysql and mariadb so i'm moving it over to the core server component for their review as i'm not sure if this is intentional behavior difference or not.

          The basic test case is this:

          presumably wrong result

          MariaDB [test]> SELECT EXTRACT(HOUR FROM '26:30:00');
          +-------------------------------+
          | EXTRACT(HOUR FROM '26:30:00') |
          +-------------------------------+
          |                             2 |
          +-------------------------------+
          1 row in set (0.00 sec)
          

          presumably correct result

          MariaDB [test]> SELECT EXTRACT(HOUR FROM '26:30:00');
          +-------------------------------+
          | EXTRACT(HOUR FROM '26:30:00') |
          +-------------------------------+
          |                            26 |
          +-------------------------------+
          1 row in set (0.00 sec)
          

          The change in behavior was introduced in 5.5.35 and later versions by this fix:

          commit b97b9536c71b3ad5ef521a1f21c527057a0a01c6 928543ca6c3f37fb1f401d5fc41c71e597e76927
          Author: Alexander Barkov <bar@mnogosearch.org>
          Date:   Mon Dec 2 15:09:34 2013 +0400
           
              MDEV-4857 Wrong result of HOUR('1 00:00:00')
          

          The change for HOUR function was obviously intentional, but one of justifications was that MySQL 5.6 had a fix. For EXTRACT, however, the behavior in all versions of MySQL is the same – "presumably correct" in the examples above. Both MariaDB KB and MySQL manual are unclear on what should actually be returned; the best that I found in the standard was this:

          If <extract field> is a <primary datetime field>, then it shall identify a <primary datetime field> of the <interval value expression> or <datetime value expression> immediately contained in <extract source>.

          "Immediately contained" probably means in our case that hours should be taken as is, rather than converted into a remainder of full days. However, it's still vague, so I'm leaving it to bar, who is both the data type expert and the author of the change, to decide if it needs to be fixed.

          elenst Elena Stepanova added a comment - The basic test case is this: presumably wrong result MariaDB [test]> SELECT EXTRACT( HOUR FROM '26:30:00' ); + -------------------------------+ | EXTRACT( HOUR FROM '26:30:00' ) | + -------------------------------+ | 2 | + -------------------------------+ 1 row in set (0.00 sec) presumably correct result MariaDB [test]> SELECT EXTRACT( HOUR FROM '26:30:00' ); + -------------------------------+ | EXTRACT( HOUR FROM '26:30:00' ) | + -------------------------------+ | 26 | + -------------------------------+ 1 row in set (0.00 sec) The change in behavior was introduced in 5.5.35 and later versions by this fix: commit b97b9536c71b3ad5ef521a1f21c527057a0a01c6 928543ca6c3f37fb1f401d5fc41c71e597e76927 Author: Alexander Barkov <bar@mnogosearch.org> Date: Mon Dec 2 15:09:34 2013 +0400   MDEV-4857 Wrong result of HOUR('1 00:00:00') The change for HOUR function was obviously intentional, but one of justifications was that MySQL 5.6 had a fix. For EXTRACT , however, the behavior in all versions of MySQL is the same – "presumably correct" in the examples above. Both MariaDB KB and MySQL manual are unclear on what should actually be returned; the best that I found in the standard was this: If <extract field> is a <primary datetime field>, then it shall identify a <primary datetime field> of the <interval value expression> or <datetime value expression> immediately contained in <extract source>. "Immediately contained" probably means in our case that hours should be taken as is, rather than converted into a remainder of full days. However, it's still vague, so I'm leaving it to bar , who is both the data type expert and the author of the change, to decide if it needs to be fixed.
          bar Alexander Barkov added a comment - - edited

          The SQL standard has two different data types:

          • TIME, to store a time of the day
          • INTERVAL DAY TO SECOND, to store a time difference between two TIMESTAMPs

          Historically, MySQL (and MariaDB) uses the same TIME data type to store both.

          The function TIMEDIFF is not standard, but obviously it returns
          (in terms of the SQL standard) a value of 'INTERVAL DAY TO SECOND",
          rather than "TIME".

          The function EXTRACT() is standard. In case when its argument
          is "INTERVAL DAY TO SECOND" in the form of "DD hh:mm:ss", then
          it returns "hh" as is, without adding DD*24.

          So in the above example, EXTRACT() follows the standard and for the given
          difference of two TIMESTAMPs it now correctly returns 9 rather than 369.

          This change was made under terms of MDEV-4857, so in this context MariaDB
          is now not compatible with MySQL. This change will help us to add the true
          INTERVAL data type soon (maybe in 10.4).

          Sorry for this inconvenience. As a simple workaround instead of EXTRACT(HOUR),
          please use the function HOUR() instead. HOUR() is not standard, so we did not
          change its behaviour:

          SET @prev_ts = '2017-11-30 11:00:00';
          SELECT NOW(),
            TIMEDIFF(NOW(),@prev_ts) AS diff,
            TIME_FORMAT(TIMEDIFF(NOW(),@prev_ts), '%H') AS 'diff TIME_FORMAT',
            EXTRACT(HOUR FROM  TIMEDIFF(NOW(),@prev_ts)) AS 'diff EXTRACT ',
            HOUR(TIMEDIFF(NOW(),@prev_ts)) AS 'diff HOUR';
          

          +---------------------+-----------+------------------+---------------+-----------+
          | NOW()               | diff      | diff TIME_FORMAT | diff EXTRACT  | diff HOUR |
          +---------------------+-----------+------------------+---------------+-----------+
          | 2017-12-23 09:43:52 | 550:43:52 | 550              |            22 |       550 |
          +---------------------+-----------+------------------+---------------+-----------+
          

          Notice, HOUR() still returns DD*24+hh.

          bar Alexander Barkov added a comment - - edited The SQL standard has two different data types: TIME, to store a time of the day INTERVAL DAY TO SECOND, to store a time difference between two TIMESTAMPs Historically, MySQL (and MariaDB) uses the same TIME data type to store both. The function TIMEDIFF is not standard, but obviously it returns (in terms of the SQL standard) a value of 'INTERVAL DAY TO SECOND", rather than "TIME". The function EXTRACT() is standard. In case when its argument is "INTERVAL DAY TO SECOND" in the form of "DD hh:mm:ss", then it returns "hh" as is, without adding DD*24. So in the above example, EXTRACT() follows the standard and for the given difference of two TIMESTAMPs it now correctly returns 9 rather than 369. This change was made under terms of MDEV-4857 , so in this context MariaDB is now not compatible with MySQL. This change will help us to add the true INTERVAL data type soon (maybe in 10.4). Sorry for this inconvenience. As a simple workaround instead of EXTRACT(HOUR), please use the function HOUR() instead. HOUR() is not standard, so we did not change its behaviour: SET @prev_ts = '2017-11-30 11:00:00' ; SELECT NOW(), TIMEDIFF(NOW(),@prev_ts) AS diff, TIME_FORMAT(TIMEDIFF(NOW(),@prev_ts), '%H' ) AS 'diff TIME_FORMAT' , EXTRACT( HOUR FROM TIMEDIFF(NOW(),@prev_ts)) AS 'diff EXTRACT ' , HOUR (TIMEDIFF(NOW(),@prev_ts)) AS 'diff HOUR' ; +---------------------+-----------+------------------+---------------+-----------+ | NOW() | diff | diff TIME_FORMAT | diff EXTRACT | diff HOUR | +---------------------+-----------+------------------+---------------+-----------+ | 2017-12-23 09:43:52 | 550:43:52 | 550 | 22 | 550 | +---------------------+-----------+------------------+---------------+-----------+ Notice, HOUR() still returns DD*24+hh .

          People

            bar Alexander Barkov
            thebreadguru MIke Thibodeau
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Git Integration

                Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.