MySQL TIMESTAMP to QDateTime with milliseconds - mysql

If I use a QSqlTableModel to access a MySQL database I can convert a TIMESTAMP field using the following:
QDateTime dateTime = index(section, column).data().toDateTime();
QString str = dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
So str shows, i.e. 2014-06-22 22:11:44.221.
But I want to access the database using QSqlQuerry, so I do:
QDateTime dateTime = query.value(column).toDateTime();
str = dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
But now I'm missing the milliseconds, str shows 2014-06-22 22:11:44.000. What's the proper way to see the milliseconds?
If I do str = query.value(column).toString(); then I get 2014-06-22T22:11:44.

From this page:
https://dev.mysql.com/doc/refman/5.6/en/datetime.html
A DATETIME or TIMESTAMP value can include a trailing fractional
seconds part in up to microseconds (6 digits) precision. In
particular, as of MySQL 5.6.4, any fractional part in a value inserted
into a DATETIME or TIMESTAMP column is stored rather than discarded.
So, the millisecond is there in MySQL! But the query.value() does not get it - at this point in the Qt history as pointed by #peppe here.
Relating back to the original question: There is no proper way to see the millisecond since the query does not have it. One alternative could be to modify the query, from:
SELECT timestamp FROM table;
to
SELECT DATE_FORMAT(timestamp, '%Y-%c-%e %H:%i:%s.%f') as timestamp FROM table;
And then finish the job with:
QString str = query.value(column).toString();
QDateTime dateTime = QDateTime::fromString(str, "yyyy-MM-dd hh:mm:ss.zzz000");
I got the insight from here.

From MySQL 5.1 documentation:
A DATETIME or TIMESTAMP value can include a trailing fractional seconds part in up to microseconds (6 digits) precision. Although this fractional part is recognized, it is discarded from values stored into DATETIME or TIMESTAMP columns.
It seems like seconds is the best you can do with timestamp.

Related

Convert Bigint data to human readable date-time in Sql

I have created a MySql table and feed data therein with below code
CREATE TABLE IF NOT EXISTS DB (
INN VARCHAR(200) NOT NULL,
Time BIGINT not NULL
);
Now I want to get a table which will report the Maximum and Minimum values of Time when grouped by INN. Below is my code -
SELECT INN, from_unixtime(MIN(Time)), from_unixtime(MAX(Time)) FROM DB GROUP BY INN
I want to get the Time values reported as normal date-time instead of Epoch time. But with above code, I am getting <NA> values.
A typical Time value is like 1546380001264082944
Can someone please help me to get the correct code to achieve the same.
The problem here is to do with the precision of the unix timestamp you are using.
Consider this:
SELECT FROM_UNIXTIME(1546380001), FROM_UNIXTIME(1546380001264082944)
The output is:
2019-01-01T22:00:01Z (null)
The timestampt value you have, 1546380001264082944, contains a level of precision beyond that accepted by MySQL.
The definition of FROM_UNIXTIME is:
FROM_UNIXTIME(unix_timestamp[,format])
The doc states:
unix_timestamp is an internal timestamp value representing seconds
since '1970-01-01 00:00:00' UTC
The precision of your timestamp is significantly greater than seconds since the Unix Epoch.
The docs are available here.
The value 1546380001264082944 is too big to be epoch seconds or even milliseconds. This is easily verified by putting this value on https://currentmillis.com/.
You have stored precision upto a nanosecond. So, divide the column value by 1e9 before passing them to from_unixtime.
SELECT INN, from_unixtime(MIN(Time) / 1000000000), from_unixtime(MAX(Time) / 1000000000)
FROM DB
GROUP BY INN

Mysql implicit conversion when comparing date column and datetime/time string

I have a table with a Date column. It has a row where my_date column's value is 2017-11-24
SELECT * FROM mytable WHERE my_date = '2017-11-24 00:00:00' returns that row.
While SELECT * FROM mytable WHERE my_date = '2017-11-24 00:00:01' does not.
From mysql doc; this page says
If one of the arguments is a TIMESTAMP or DATETIME column and the
other argument is a constant, the constant is converted to a timestamp
before the comparison is performed. This is done to be more
ODBC-friendly. This is not done for the arguments to IN().
If I am interpreting this correctly, in the second query, the constant on right side would be implicitly casted to Date field
The second page for casting says -
Conversion to a DATE value takes fractional seconds into account and
rounds the time part. For example, '1999-12-31 23:59:59.499' becomes
'1999-12-31', whereas '1999-12-31 23:59:59.500' becomes '2000-01-01'.
The example shows 1999-12-31 23:59:59.499 -> 1999-12-31. I understand explicit casting is preferred, but I am wondering why mysql chose to typecast the column value instead of constant or if there's something else happening here.
I don't think you are interpreting the docs correctly. The first page you quote is about comparing a DATETIME or TIMESTAMP to a constant. You are comparing a DATE to a constant, so this logic should apply:
Conversion of DATE values:
Conversion to a DATETIME or TIMESTAMP value adds a time part of '00:00:00' because the DATE value contains no time information.
So it's like comparing '2017-11-24 00:00:00' = '2017-11-24 00:00:01' which sensibly returns false.
Comparing DATEs to DATETIMEs/TIMESTAMPs is similar to comparing an int to a double in that the implicit conversion applies to the less precise value. You would not expect 42 to match 42.1, and likewise you shouldn't expect 2017-11-24 to match 2017-11-24 00:00:01.

Remove milliseconds in a datetime field

I converted a database from MS SQL to MySql using workbench. There is a table that has a column called ActivityDate (datetime(6)) . For some reason, when that column got converted it has a dot in the date like (2013-05-03 11:20:20.420000) .
I want to remove the .420000 or whatever number is after the dot. I tried doing SUBSTRING_INDEX(ActivityDate,'.',1) but that didn't work, the last digits would just be .000000
I also tried UPDATEalerts.activitylogSETActivityDate= date_format(ActivityDate, '%Y-%m-%d %H:%i') WHEREactivitylog.ActivityLogID= 5;
And same issue... I get .000000 at the end
How can I do this?
Simply change the data type of the column to exclude the fractional part.
ALTER TABLE alerts.activitylog MODIFY ActivityDate DATETIME;
The type datetime(6) means 6 digits after the decimal point.
See the MySQL date and time fractional support documentation for details.
If you just want to select the datetime without the ms (like I was when I found this question) then the below CAST does the job:
SELECT CAST(created_at AS DATETIME) AS created_at_without_ms

MySQL varchar timestamp column stored two different ways

I have a table with device data, one of the columns created_ts -> varchar(30)
The problem: this data in this column contains both linux timestamps and varchars for example:
1381148885
and
2012-09-17 22:13:17
How can I query this column for all records with created_ts > 2013-10-01
I'd opt for distinguishing between the string formats (either 'YYYY-MM-DD' or unix timestamp integer) by checking for a dash character.
I'd consider explicitly converting both of those formats to the DATE datatype, using an appropriate conversion. I'd compare the resulting DATE value with the date literal.
Something like this:
WHERE IF(LOCATE('-',t.created_ts,5), -- which format (yyyy-mm-dd or integer)
STR_TO_DATE(t.created_ts,'%Y-%m-%d %T'), -- convert yyyy-mm-dd string to date
FROM_UNIXTIME(t.created_ts) -- convert string as integer to date
) >= '2013-10-01' -- compare to date literal
Another option would be to convert the string column and the date literal to integer values, and do an integer comparison. (Again, two different conversions for the string column, depending on the format.)
NOTE: I included the hh:mm:ss portion in the conversion with the %T.
When no time component is supplied, the time components is assumed to be midnight (zeros) 00:00:00, and that comes into play depending on whether or not we want to consider
'2013-10-01 07:34:55' > '2013-10-01 00:00:00'
OP query has a greater than comparison. I used a greater than or equal to comparison.
This could all be adjusted, depending on the requirements. We want to be aware that if we aren't careful, some values will get "rounded down" to the previous midnight, and then when we do a greater than comparison, what we're really getting is equivalent to >= '2013-10-02'.
My preference is to make it more explicit. It makes it easier for the reader to understand what the query is actually doing.
UPDATE
I had the arguments in the LOCATE function backwards... the string to search for should be the first argument, the string to be searched is second. That's been corrected in the query above.
Something like this:
select * from yourTable
where created_ts > '2013-10-01'
or from_unixtime(created_ts) > '2013-10-01';

MySQL compare date with timestamp

I have a VARCHAR field completion_date that contains a timestamp date (ex 1319193919). Is it possible to run a query on such a field that compares it with NOW() ? I'm trying:
SELECT * FROM (`surveys`) WHERE `active` = '1' AND `archived` = '0' AND `completion_date` > 'NOW()'
But the results are not really what I'm expecting, is this cause of the VARCHAR? If so, what kind of date field am I better off using? The data must remain a Linux timestamp.
Convert NOW() to a timestamp using UNIX_TIMESTAMP()
SELECT *
FROM (`surveys`)
WHERE `active` = '1' AND `archived` = '0' AND `completion_date` > UNIX_TIMESTAMP(NOW())
Also, remove the quotes you had around 'NOW()'
mysql> SELECT UNIX_TIMESTAMP(NOW());
+-----------------------+
| UNIX_TIMESTAMP(NOW()) |
+-----------------------+
| 1319288622 |
+-----------------------+
N.B. In case you need it, the inverse of this function is FROM_UNIXTIME() to convert a timestamp into the default MySQL DATETIME format.
As mentioned in comments below, if you have the ability to make the change, it is recommended to use a real DATETIME type instead of VARCHAR() for this data.
A Linux timestamp can easily be stored in a BIGINT (or an UNSIGNED INT), which would make the type of comparisons you're trying to do possible. A VARCHAR is going to do a lexical, not numeric, comparison and which is NOT what you want. Using a BIGINT in conjunction with converting NOW() with UNIX_TIMESTAMP() should get you what you want.
It might even be better to store it using a DATETIME data type and do the conversion when you select the data. Storing it as a DATETIME future proofs your application in the event that you move to or add a different platform where a Linux timestamp isn't appropriate. Then you only need to modify your code, not convert your data to have it continue to work. I'm working on a project now where dates were stored as character data and it's been no end of problems getting the old data into shape to use with the new application, though you might experience fewer problems than us because you're storing a time stamp, not a formatted date, with its attendant typos.