DATETIME comparisons? - mysql

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().

Related

mysql between 2 dates does not working with 2 different months

Hello i need expert advice for my mysql query
I'm trying to filter values between 2 months
If start day lower then end day of different months all working well
But if i try higher day value on start return none
this is working code
SELECT id, teslim_tarihi AS tarih, toplam, marka, model, malzeme
FROM ariza
WHERE durum = '7' AND (teslim_tarihi BETWEEN '01-02-2018 00:00' AND '01-03-2018 23:59')
ORDER BY tarih DESC
Not working at all
SELECT id,teslim_tarihi as tarih ,toplam,marka,model,malzeme
FROM ariza
WHERE durum = '7' AND (teslim_tarihi BETWEEN '14-02-2018 00:00' AND '01-03-2018 23:59')
ORDER BY tarih DESC
date format dd-mm-yyyy H:i
As has been suggested by #stackFan, it really does make considerable sense to stick with mysql's default date and time formats. However, for whatever reason, you seem to be stuck with a different format so I'll attempt to work with that.
Your current query isn't working in your second example because mysql doesn't recognise these as dates and a strings starting '14-02-2018' is greater than another string starting '01-03-2018'. e.g.
SELECT '14-02-2018' > '01-03-2018';
+-----------------------------+
| '14-02-2018' > '01-03-2018' |
+-----------------------------+
| 1 |
+-----------------------------+
The values when using BETWEEN ... AND have to have the min value first and the max value Documentation, so in your second example the comparison is the wrong way round because '14-02-2018' is greater than '01-03-2018', hence no rows returned.
You didn't answer the query about the data type of your column teslim_tarihi which would have made answering your query simpler. I'll assume it is a DATETIME or TIMESTAMP. Your comparison should be made against something that mysql knows to be a date or recognises as a date and that means getting the dates into YYYY-MM-DD or YY-MM-DD format. Mysql will helpfully cast values to the appropriate type if the format is one it recognises. e.g.
SELECT DATE '2018-02-14' < '2018-03-01';
+-----------------------------------+
| DATE '2018-02-14' < '2018-03-01' |
+-----------------------------------+
| 1 |
+-----------------------------------+
You should be able to get the query working by turning your strings into dates in the following manner.
SELECT DATE '2018-03-01'
BETWEEN STR_TO_DATE('14-02-2018 00:00', '%d-%m-%Y %H:%i')
AND STR_TO_DATE('01-04-2018 23:59','%d-%m-%Y %H:%i') 'between dates';
+---------------+
| between dates |
+---------------+
| 1 |
+---------------+
If your column teslim_tarihi is a VARCHAR, then convert that in the same manner to get the query to work.
As per the documentation the default format of date in MySQL is YYYY-MM-DD. Can you try using this query instead?
SELECT id,teslim_tarihi as tarih ,toplam,marka,model,malzeme
FROM ariza
WHERE durum = '7' AND (teslim_tarihi BETWEEN '2018-02-14 00:00:00' AND '2018-03-01 23:59:59')
ORDER BY tarih DESC

Possibly Mysql 5.6.20 bug. Date - now()?

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

Difference between NOW(), SYSDATE() & CURRENT_DATE() in MySQL

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 INTERVAL required for datetime arithmetic in MySQL?

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 |
+---------------------------------------------------------+

How do I convert negative time value into 24 hour time in MYSQL?

I have a column in a table of type TIME. I want to get a result that applies a time shift that results in a 24 hour clock representation of that shift. To add the shift, my query contains...
select addtime(boo,'01:00:00') as yada
But any value that gets taken out of the 24 hour range ends up outside the 24 hour range, such as...
23:45 ends up as 24:45 (when I want 00:45:00)
If I go the other way and subtract the hour from a value less than 1am, I get...
00:15 ends up as -00:45:00 when I want (23:15:00)
Now, I understand that the TIME format in MYSQL is "duration" and not the actual "time", but for the life of me I can't figure out how to convert to an actual clock time as outlined above. Please help me or kill me. Either will end my suffering.
A simple solution would be to just use a DATETIME data type instead, then ignore the date part. If you're not dealing with huge amounts of data, or searching by the actual times I can't see an issue.
As a bonus you'll be able to manipulate the data with the likes of + INTERVAL 1 HOUR etc.
When extracting it just use TIME(boo)
As you know, the MySQL TIME type is not restricted to 24 hour time so this is probably the closest you'll get... I'm sure you could construct a query using MOD() etc but it's probably not worth it.
A possible solution is just add your boo TIME value to any date (e.g. today) then add your time delta and after that just return time part with TIME()
SELECT TIME(CURDATE()
+ INTERVAL TIME_TO_SEC('23:45:00') SECOND
+ INTERVAL 1 HOUR) new_time
Output:
+----------+
| new_time |
+----------+
| 00:45:00 |
+----------+
Here is SQLFiddle demo