I know that the code is incorrect and that the ADDDATE function should be used, but I'm trying to find out if a specific behaviour is caused by this bug.
So, does anyone know what exactly happens if I have the statement
SELECT * FROM MyTable WHERE TheTimestamp > (NOW()-86400);
when TheTimestamp is of the datetime data type?
It's not a bug. You're just expecting a datetime cast to a number to be something it's not.
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-literals.html says:
MySQL recognizes DATETIME and TIMESTAMP values in these formats:
...
As a number in either YYYYMMDDhhmmss or YYMMDDhhmmss format, provided that the number makes sense as a date. For example, 19830905132800 and 830905132800 are interpreted as '1983-09-05 13:28:00'.
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-types.html says:
MySQL automatically converts a date or time value to a number if the value is used in numeric context and vice versa.
So using NOW() in an arithmetic expression converts it to a number:
mysql> SELECT now(), now() + 0;
+---------------------+----------------+
| now() | now() + 0 |
+---------------------+----------------+
| 2022-10-19 14:13:14 | 20221019141314 |
+---------------------+----------------+
You can see this converts '2022-10-19 14:13:14' (the date and time I test this query) into an integer simply by removing the punctuation and whitespace. This isn't a number you can add or subtract with, because the values 60-99 aren't used for seconds or minutes, and likewise the values 24-99 for hours, 32-99 for days, 13-99 for months, etc.
The expression you showed doesn't produce a number that is valid as a timestamp:
mysql> SELECT now(), now() - 86400;
+---------------------+----------------+
| now() | now() - 86400 |
+---------------------+----------------+
| 2022-10-19 14:20:09 | 20221019055609 |
+---------------------+----------------+
^^ there is no time with 56 minutes
^^^^ yesterday's date should be 10/18
To do arithmetic on the datetime, you should either convert to a integer measure of seconds, then use that value in integer expressions:
mysql> SELECT now(), unix_timestamp(now());
+---------------------+-----------------------+
| now() | unix_timestamp(now()) |
+---------------------+-----------------------+
| 2022-10-19 14:16:57 | 1666214217 |
+---------------------+-----------------------+
Or else use MySQL's support for temporal INTERVAL expressions. See https://dev.mysql.com/doc/refman/8.0/en/expressions.html#temporal-intervals
mysql> select now(), now() - interval 86400 second;
+---------------------+-------------------------------+
| now() | now() - interval 86400 second |
+---------------------+-------------------------------+
| 2022-10-19 14:24:01 | 2022-10-18 14:24:01 |
+---------------------+-------------------------------+
DATETIME and TIMESTAMP values are implicitly integer values of 5 and 4 bytes in length respectively (with optional additional bytes for fractional seconds precision). Mathematical operators, as well as conditional operators, will work accordingly. However, this will not account for all the implicit conversions like when you use ADDTIME().
This operation specifically looks for any records created later than 1 day ago, since the DATETIME value has to be greater than (later in time) the current time - 86400 seconds (1 day/24 hours) ago.
Related
I have birth dates stored in a MySQL database that I need converted to a readable date format yyyy-mm-dd hh:mm:ss. I cannot use the MySQL's From_Unix function as many birth dates are before 1970 and the function returns NULL. (i.e. -866138400000 which is 07/21/1942)
I have tried to use ticks but that is also returning NULL:
(FROM_DAYS(365 + (req.PATIENTDOB / 864000000000)) + INTERVAL (req.PATIENTDOB % 864000000000) / 10000000 SECOND) AS ptDob
Any advance would be greatly appreciated. Thank you.
I have no idea why you're making things so complicated. Just divide by 1000 to get seconds instead of microseconds and subtract that from 1970-01-01.
mysql > select '1970-01-01' + interval -866138400000/1000 second;
+---------------------------------------------------+
| '1970-01-01' + interval -866138400000/1000 second |
+---------------------------------------------------+
| 1942-07-22 06:00:00 |
+---------------------------------------------------+
1 row in set (0.00 sec)
So your query would actually be this of course:
select '1970-01-01' + interval your_column / 1000 second from your_table;
This query proves, that your assumption, that it would be 1942-07-21 is wrong. 1942-07-22 is correct.
mysql > select timestampdiff(second, '1942-07-21', '1970-01-01');
+---------------------------------------------------+
| timestampdiff(second, '1942-07-21', '1970-01-01') |
+---------------------------------------------------+
| 866246400 |
+---------------------------------------------------+
Found an answer while researching Negative Epochs. I was able to use the From_Unixtime function after all!
select date_format((DATE_ADD(FROM_UNIXTIME(0), interval -866138400000/ 1000 second)),'%Y-%m-%d') as ptdate;
-> "1942-07-21"
Link to Reference > Look under Negative Epochs section
date_newOrd, now(), date_newOrd-now() AS `time`
this is my query. date_newOrd is type date. I try to calculate the time remaining for next arrival of order. I better show you the screenshot:
the result is doesn't make any sense. What am i supposed to do>
You cannot subtract dates like that:
mysql> select '2015-06-01 18:20:03' - now();
+-------------------------------+
| '2015-06-01 18:20:03' - now() |
+-------------------------------+
| -20150602073525 |
+-------------------------------+
While that may look (vaguely) like a date, it's really an integer, and can't be used for further date math without extra processing.
You have to use datediff() or timediff():
mysql> select timediff('2015-06-01 18:20:03', now()) as td, datediff('2015-06-01 18:20:03', now()) as dd;
+-----------+------+
| td | dd |
+-----------+------+
| -13:37:47 | -1 |
+-----------+------+
note that datediff deals only with DATES, and timediff deals with datetime values.
When you do a subtraction, MySQL is going to evaluate NOW() in a numeric context, it returns a numeric value.
SELECT NOW()+0
20150602135210.000000
So, your statement is doing a subtraction of numbers, not doing a DATE calculation.
Some possibilities:
You could convert the datetime values into unix_timestamp values, (UNIX_TIMESTMAP() function) and then do a subtraction of those to get a difference in integer seconds.
The DATEDIFF() function would get you a difference in integer days. (That operates only on the date portion, it ignores the time... so that probably doesn't give you the resolution you are looking for.)
The TIMESTAMPDIFF() and TIMEDIFF() functions are also available. (The TIMEDIFF functions returns a TIME datatype value; the maximum value of that datatype is 838:59:59, so that's limited to just under 35 days elapsed).
For example:
SELECT UNIX_TIMESTAMP('2015-06-03') - UNIX_TIMESTAMP(NOW()) AS secs
secs
-------
35856
I'm trying to switch from using UNIX timestamps to DATETIME columns in MySQL and am having a little trouble finding the correct way to make comparisons between dates.
I tried using the + and - operators to compare two DATETIMEs and the results don't make any sense to me.
For example:
1.
SELECT UTC_TIMESTAMP(), UTC_TIMESTAMP() - INTERVAL 1 HOUR
Outputs
2014-07-06 19:19:13 | 2014-07-06 18:19:13
These
SELECT UTC_TIMESTAMP() - DATE_SUB(UTC_TIMESTAMP(), INTERVAL 1 HOUR)
SELECT UTC_TIMESTAMP() - (UTC_TIMESTAMP() - INTERVAL 1 HOUR)
Both output 10000. This number doesn't make sense to me, but then it gets more confusing as this:
SELECT UTC_TIMESTAMP()-DATE_SUB(UTC_TIMESTAMP(), INTERVAL 1 SECOND)
Outputs 1. Why is that? What does that number represent?
2.
The manual page for date and time functions shows DATE_ADD() and DATE_SUB() can be used to add and subtract intervals from dates, but I don't see any functions in the manual that correspond to the great than and less than operators, so how would I check to see if the current date is greater than some other date?
I tried using the < and > operators and they seem to work, but I can't seem to find anything on this in the manual and want to make sure it's OK to use these operators like this:
SELECT UTC_TIMESTAMP() > DATE_SUB(UTC_TIMESTAMP(), INTERVAL 1 HOUR)
Can anyone demystify DATETIME comparisons in MySQL?
To quote the documentation about UTC_TIMESTAMP():
Returns the current UTC date and time as a value in 'YYYY-MM-DD
HH:MM:SS' or YYYYMMDDHHMMSS format, depending on whether the function
is used in a string or numeric context.
Because the value is being used in the context of a number, it is treated as a number, which is the behavior that you see.
I've just found this out myself, but here's a quick example that shows you how it works.
#GordonLinoff's answer is neither here nor there, because your question isn't really about the format returned from utc_timestamp(). What you're really asking is what format does MySQL return when you use numeric operands + and - on timestamps.
I tend to agree with you that the documentation is a bit fuzzy on the topic. But this is what I found. You can build this view yourself to see the example in simpler terms.
create view cbhview as
select utc_timestamp() as nowtime,
utc_timestamp() - interval 1 hour as thentime,
date_sub(utc_timestamp(),INTERVAL 1 HOUR) as thentime2,
date_sub(utc_timestamp(),INTERVAL 1 SECOND) as justthentime;
select nowtime, thentime, thentime2, justthentime,
nowtime-thentime,
nowtime-justthentime,
thentime-thentime2
from cbhview;
+---------------------+---------------------+---------------------+---------------------+------------------+----------------------+--------------------+
| nowtime | thentime | thentime2 | justthentime | nowtime-thentime | nowtime-justthentime | thentime-thentime2 |
+---------------------+---------------------+---------------------+---------------------+------------------+----------------------+--------------------+
| 2014-07-06 20:22:58 | 2014-07-06 19:22:58 | 2014-07-06 19:22:58 | 2014-07-06 20:22:57 | 10000 | 1 | 0 |
+---------------------+---------------------+---------------------+---------------------+------------------+----------------------+--------------------+
1 row in set (0.00 sec)
100000 represents 1h 00min 00second
1 represents 1second
0 represents no difference between the two
In short, unless you know exactly what you're doing and exactly what you're trying to achieve, don't use numeric operands on date and timestamp datatypes. Keep to the functions that have been designed for the purpose date_add() and date_sub().
What difference between NOW() , SYSDATE() , CURRENT_DATE() in MySQL and where it can be used in real scenario .
I tried NOW(),SYSDATE(),Current_Date() when I insert data into a table and column datatype is TIMESTAMP all are given same date and time.
Current_date() will only give you the date.
now() give you the datetime when the statement,procedure etc... started.
sysdate() give you the current datetime.
Look at the seconds after waiting 5 seconds between now()1 sysdate()1 with the following query (scroll to the right):
select now(),sysdate(),current_date(),sleep(5),now(),sysdate();
-- will give
-- now() sysdate() current_date() sleep(5) now()1 sysdate()1
-- 6/10/2014 2:50:04 AM 6/10/2014 2:50:04 AM 6/10/2014 12:00:00 AM 0 6/10/2014 2:50:04 AM 6/10/2014 2:50:09 AM
NOW() returns a constant time that indicates the time at which the statement began to execute. (Within a stored function or trigger, NOW() returns the time at which the function or triggering statement began to execute.) This differs from the behavior for SYSDATE(), which returns the exact time at which it executes.
mysql> SELECT NOW(), SLEEP(2), NOW();
+---------------------+----------+---------------------+
| NOW() | SLEEP(2) | NOW() |
+---------------------+----------+---------------------+
| 2006-04-12 13:47:36 | 0 | 2006-04-12 13:47:36 |
+---------------------+----------+---------------------+
mysql> SELECT SYSDATE(), SLEEP(2), SYSDATE();
+---------------------+----------+---------------------+
| SYSDATE() | SLEEP(2) | SYSDATE() |
+---------------------+----------+---------------------+
| 2006-04-12 13:47:44 | 0 | 2006-04-12 13:47:46 |
+---------------------+----------+---------------------+
Current_date returns the time stamp of the client while sysdate returns the time stamp of the server. If both server and the client are on the same machine, then, the result of both commands are the same. But in case that your sever is for example in USA and your clients are in China, then, these two functions return completely different results.
I don't know about thew now(), sorry :-)
One of the major differences between sysdate() and now() recently bit me in the behind. It was the difference in the point-in-time and frequency of their execution. sysdate() is evaluated every time within the same statement--ie, in every row to which it applies. But now() will only be evaluated only once, which is at the start of query execution.
This difference isn't noticeable when there are only a few rows. But it's very significant when there are millions of rows. In RHEL7, for example, sysdate() apparently makes a costly system call, so that when there are millions of rows, using sysdate() took more than an hour, but using now() in the exact same statement took only several seconds!
This is on top of precision issues, because sysdate() will return a different value, for example, between time t and time t+50 millis.
With regard to curdate(), I was also wondering how it's different from either now() or sysdate(). The MySQL Reference says that, with regard to when and how many times it's executed, curdate() behaves like now().
Reference: MySQL 5.7 Reference - Date and Time Functions -- All of the above is described in this page. However, it's scattered on the page, so you'll have to read through the overview section as well as the reference for each function.
CURRENT_DATE() is a synonym for many other similar functions all of which provide only the date.
There is a subtle difference between NOW() and SYSDATE() which you can read up more on this official MySQL website page.
CURRENT_DATE is static and works better with date indexes.
NOW() seems dynamic and does not benefit from index. (I would love to hear a comment on the subject with more detail on the MySQL internals here!)
Here's a real-world example using NOW():
explain SELECT DISTINCT e.manager_id, m.manager_name FROM events e JOIN manager m ON m.manager_id = e.manager_id
WHERE m.manager_name != '' AND e.event_when > NOW() - INTERVAL 1 YEAR;
+---------+----------+------------------------------+
| rows | filtered | Extra |
+---------+----------+------------------------------+
| 1333648 | 29.06 | Using where; Using temporary |
| 1 | 90.59 | Using where |
+---------+----------+------------------------------+
You can see the number of rows are reduced substantially using CURRENT_DATE (or CURRENT_TIMESTAMP):
explain SELECT DISTINCT e.manager_id, m.manager_name FROM events e JOIN manager m ON m.manager_id = e.manager_id
WHERE m.manager_name != '' AND e.event_when > CURRENT_DATE - INTERVAL 1 YEAR;
+--------+----------+----------------------------------------+
| rows | filtered | Extra |
+--------+----------+----------------------------------------+
| 361470 | 100.00 | Using index condition; Using temporary |
| 1 | 90.59 | Using where |
+--------+----------+----------------------------------------+
NOW() returns a constant time that indicate's the time at which the statement began to exicute whereas SYSDATE () returns the time at which it exicute... OR in other words NOW ()shows query exicution time and SYSDATE() shows self exicution time..
Is it always necessary to use the interval function in MySQL when using math to create relative dates?
I use Date()-Weekday(Date()) in MS-Access 2010 and tried curdate() - dayofweek(curdate()) in MySQL. I got some obscure number, and after searching found this StackOver answer that accomplishes what I want to.
After reading this support article I want to be sure I understand this right--any time I want to do simple math with date functions, I have to use the interval function and declare what unit of time I want to work with?
If I don't use the interval function, is there any use for the number I get from curdate() - dayofweek(curdate())?
I've never used interval before, and I'm just used to MS products treating date format and number format as one in the same. Looking for some clarification.
There is no use for the number you got back from curdate() - dayofweek(curdate()).
SELECT curdate() - dayofweek(curdate())
+----------------------------------+
| curdate() - dayofweek(curdate()) |
+----------------------------------+
| 20140097 |
+----------------------------------+
What you're looking at there is the result of the number 20140103 minus the number 6 and it bears no resemblance to any usable date:
> select 20140103 - 6;
+--------------+
| 20140103 - 6 |
+--------------+
| 20140097 |
+--------------+
Because you didn't use INTERVAL, MySQL appears to have cast the date 2014-01-03 into the number 20140103 and the result when subtracting the current weekday (6) is nonsense. (I'm actually surprised that happened - I would have expected an error or a different result1).
You do need to use the INTERVAL specifier for simple arithmetic or when using many of MySQL's date/time functions.
In some cases you could get around using INTERVAL if you converted values to and from integers as Unix timestamps via UNIX_TIMESTAMP(datetime), FROM_UNIXTIME(datetime). It's tricky to get right though and I recommend using the real date/time functions to work with actual DATE/DATETIME values whenever possible.
select curdate() - INTERVAL dayofweek(curdate()) DAY;
+-----------------------------------------------+
| curdate() - INTERVAL dayofweek(curdate()) DAY |
+-----------------------------------------------+
| 2013-12-28 |
+-----------------------------------------------+
1 row in set (0.00 sec)
That's more like it :)
1 I don't have an explanation for the casting behavior that occurred, because I would have expected this instead. Needless to say though, it's not something you should be using or relying on:
SELECT CAST('2014-01-03' AS UNSIGNED);
+------------------------------+
| CAST('2014-01-03' AS UNSIGNED) |
+------------------------------+
| 2014 |
+------------------------------+
... Actually, here it is casting a DATE to an unsigned INTEGER:
SELECT CAST(STR_TO_DATE('2014-01-03', '%Y-%m-%d') AS UNSIGNED);
+---------------------------------------------------------+
| CAST(STR_TO_DATE('2014-01-03', '%Y-%m-%d') AS UNSIGNED) |
+---------------------------------------------------------+
| 20140103 |
+---------------------------------------------------------+