node-mysql2 icon indicating copy to clipboard operation
node-mysql2 copied to clipboard

datetime fields returned as date when time is 00:00:00

Open lirancr opened this issue 6 years ago • 9 comments

Setting a DATETIME field with the value 2019-10-01 00:00:00 Then retrieve the data using the execute command: const [result] = connection.execute('SELECT * FROM my_table', [])

result will equal to '2019-10-01' instead of '2019-10-01 00:00:00' although it's a DATETIME field and not merely a DATE

note that when using query the behavior is as expected

lirancr avatar Oct 21 '19 12:10 lirancr

could you post simple self contained example, including schema creation and initial data insert?

sidorares avatar Oct 21 '19 12:10 sidorares

Sure here is a standalone snippet

    //running with node 10.16.0 using mysql2 ^1.7.0

    const mysql = require('mysql2/promise');

    async function main() {
    let db = await mysql.createConnection({
        host: 'localhost',
        port: '3306',
        user: 'root',
        password: 'root'
    });
    await db.query("SET time_zone='+00:00'");
    await db.query('DROP DATABASE IF EXISTS test_db');
    await db.query('CREATE DATABASE IF NOT EXISTS test_db');
    await db.close();

    db = await mysql.createConnection({
        host: 'localhost',
        port: '3306',
        user: 'root',
        password: 'root',
        database: 'test_db',
        dateStrings: true,
        timezone: '+00:00'
    });

    await db.query('CREATE TABLE IF NOT EXISTS mytbl (id INT AUTO_INCREMENT, created DATETIME NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB');
    await db.execute('INSERT INTO mytbl (created) VALUES (?)',['2019-10-01 00:00:00']);
    let [result] = await db.execute('SELECT * FROM mytbl', []);
    console.log('execute result',result[0]);
    [result] = await db.query('SELECT * FROM mytbl', []);
    console.log('query result',result[0]);
    
    }

    main();

scratches.zip

lirancr avatar Oct 21 '19 13:10 lirancr

Data in db has DATETIME type, but actual value only contain 4 bytes ( 2 for year, 1 for month and 1 for day ) - this is where it gets deserialized to a string ( note that there is no intermediate conversion to JS Date when you pass dateStrings: true option: https://github.com/sidorares/node-mysql2/blob/aa0f727db692f8efb0646746ad6eb5ef187e0fe6/lib/packets/packet.js#L303-L306

I agree, result of (await db.execute|query('SELECT * FROM mytbl')[0][0]).toString() should be all the same for dateStrings: true and dateStrings: false

I guess the fix should be to append 00:00:00 when it's just 4 bytes of datetime returned

Do you want to volunteer to fix this @lirancr ?

sidorares avatar Oct 22 '19 02:10 sidorares

Of course. Any reason why query behaves differently ?

lirancr avatar Oct 22 '19 08:10 lirancr

Any reason why query behaves differently ?

execute and query serialise responses very differently, for query results come as text and for execute - binary encoded

In the above example when dateStrings is set to true for query we return just whatever was in query response and with execute we construct date as string from binary data we have ( 4 bytes ). When dateStrings is not set in both execute and query we construct js Date object

sidorares avatar Oct 22 '19 12:10 sidorares

Done, see associated PR

lirancr avatar Oct 23 '19 13:10 lirancr

Travis CI tests fail for some reason, I'll have a look tomorrow

sidorares avatar Oct 23 '19 13:10 sidorares

any update on this ? let me know if there's something i do to help out

lirancr avatar Oct 28 '19 08:10 lirancr

hi, when will #1147 be merged?

deko2369 avatar Oct 21 '21 05:10 deko2369