I'm trying to figure out what MySQL is doing during the math operation of timestamps.
Picture of resulting problem:
You'll see on the left I have two timestamps, start and end, and I need to find the duration from start to end so I just do this:
end - start
I was getting some really weird results. You can see for a duration of only 3 hours I was getting result back that indicated 2 to 3 times that amount.
When I convert to UTC first, the math works out fine.
Can anyone explain what SQL is doing with the timestamps on the left? I've always been under the impression that all timestamps are UTC under the hood, which is why things like min, max, less than, etc work without converting.
Thanks!
Code:
select
min(timestamp) start,
max(timestamp) end,
max(timestamp) - min(timestamp) start_to_end,
unix_timestamp(min(timestamp)) startUTC,
unix_timestamp(max(timestamp)) endUTC,
unix_timestamp(max(timestamp)) - unix_timestamp(min(timestamp)) start_to_end_UTC
from post_snapshots group by permalink;
These examples have nothing to do with timezone conversions -- when you subtract one date directly from the other, MySQL generates a integer from all existing date parts and then makes the math operations. For example, this query:
select now()+1;
returns (it was '2013-02-26 14:38:31' + 1):
+----------------+
| now()+1 |
+----------------+
| 20130226143832 |
+----------------+
So the difference between "2013-02-19 16:49:21" and "2013-02-19 19:07:31" turns out to be:
20130219190731 - 20130219164921 = 25810
The correct way for getting this subtraction is to either convert the dates to timestamps (like you did) or to use TIMESTAMPDIFF(SECOND, start_date, end_date), which would return 8290.
This isn't a DATETIME vs. TIMESTAMP or a time zone problem.
MySQL handles datetimes as operands to a subtraction (or other mathematical operation) by converting each value to a number, but it's not the number of seconds, its just the datetime digits crunched together. Take an example from your data:
2013-02-19 16:49:21 becomes 20130219164921
2013-02-19 19:07:31 becomes 20130219190731
The difference between those two numbers is... 25810, which is the value you're seeing as the result of your subtraction operation. That's not a result in seconds, as you noted. It really doesn't mean much useful at all.
In contrast, TIMESTAMPDIFF() (or pre-converting to Unix timestamps as you did) actually performs the difference using time-appropriate math if you're looking for the difference to be significant for much beyond sorting:
SELECT TIMESTAMPDIFF(SECOND, '2013-02-19 16:49:21', '2013-02-19 19:07:31')
>>> 8290
What happens is you cannot substract dates/datetimes in mysql. For all math operations, the mysql timestamp data type behaves like datetime data type.
You could use instead
select
TIMESTAMPDIFF(SECOND,min(timestamp),max(timestamp))
from post_snapshots group by permalink;
Related
I am using DATE() function to calculate the difference between two dates in MySQL
value of SYSDATE() function is following
select SYSDATE();
2020-07-15 12:16:07.0
When I am using date from same month, it is giving correct result
select DATE(SYSDATE())- DATE('2020-07-13');
2
But when I am using date from last month it is giving difference as 86 instead of 16;
select DATE(SYSDATE())- DATE('2020-06-29');
86
Edit:
I am aware that we can use DATEDIFF() but I want to verify why DATE() function is giving results like this since we are already using this in code
MySQL doesn't support subtracting one date from another. The code
SELECT DATE '2020-07-15' - DATE '2020-06-29';
should hence result in an error, but MySQL silently converts this to this instead:
SELECT 20200715 - 20200629;
Seeing that you want to subtract two values, it assumes that you want to work with numbers. Dates are not numbers, but their internal representation yyyymmdd can be represented numerically. So, while CAST(DATE '2020-07-15 ' AS int) fails with a syntax error, as it should, MySQL is not consistent, when it comes to subtraction. It generates the numbers 20200715 and 20200629 and works with these.
I consider this a bug. MySQL should either raise an exception or return an INTERVAL when subtracting one DATE from another.
I am currently working on a ticket system in which I would like to work out the average amount of time it is taking staff to respond to tickets.
I have 2 columns that hold the UNIX timestamps: timestamp (when ticket was submitted) and endstamp (when ticket was closed)
SELECT AVG(TIMEDIFF(endstamp,timestamp)) AS timetaken FROM `tickets`
I'm not really sure what I am doing wrong.
Any help would be much appreciated!
A UNIX timestamp is just a representation of a point in time as a number of seconds, so basically an integer value. On the other hand, date function timestampdiff() operates on 3 parameters: a unit, and two values (or expressions) of datetime datatype (or the-like). Your query should actually raise a syntax error, since what you are giving as first argument is not a legal unit.
If you want the difference in seconds between two UNIX timestamps, just substract them, so:
SELECT AVG(endstamp - timestamp) AS timetaken FROM `tickets`
I'm having a problem working with a Navicat Database. I got a column in SQL called fechaNacimiento (Birthdate) that should be a Date type, but instead it's stored as integers (most negative integers):
SELECT fechaNacimiento FROM Registrados
And I'm getting:
fechaNacimiento
-1451678400
-2082829392
-1798746192
-1199221200
-1356984000
-694299600
-1483214400
-1924976592
-1830368592
-2019670992
-1678909392
239252400
1451617200
-879541200
I don't know how this dates where loaded, I just know that inside that negative integer there's a date, and nobody here have any clue about how to spell SQL, so I have nobodoy to ask. If I just cast it to DATETIME, I get all of them as NULL values. Any idea in how to convert this data to Date type?
Numbers like that make me think of Unix times, number of seconds since 1970. If so, you might be able to do:
select dateadd(second, <column>, '1970-01-01')
This would put the negative values sometime before 1970 (for instance, -1678909392 is 1916-10-19). If you have older dates, then that might be the format being used.
These might also be represented as milliseconds. If so:
select dateadd(second, <column>/1000, '1970-01-01')
In this case, -1678909392 represents 1969-12-12.
In MySQL, you would use:
select '1970-01-01' + interval floor(column / 1000) second
There is a table with DATETIME field named 'created_at'.
I try execute two queries like this:
SELECT * FROM myTable WHERE created_at BETWEEN '2015-03-15 10:25:00' AND '2015-03-25 10:30:00';
SELECT * FROM myTable WHERE created_at BETWEEN
STR_TO_DATE('2015-03-15 10:25:00', '%Y-%m-%d %H:%i:%s') AND STR_TO_DATE('2015-03-25 10:30:00', '%Y-%m-%d %H:%i:%s');
I always used the first query, but recently came across an article in which describes that the second approach is the best way to compare DATETIME. Unfortunately, it does not contain any explain why that approach is the best way.
Now, I have some questions:
Is there any difference between these two approaches?
Which way is more preferable?
Thanks!
I much prefer to put the constants in directly. I believe that MySQL will process the str_to_date() function only once for the query, because the arguments are constants. However, I don't like to depend on this optimization.
The advantage to str_to_date() is that it should be independent of internationalization settings so the result should be unambiguous. However, the use of ISO standard formats should be equivalent, and that is the structure of your constants.
However, that aside, a better way to write the query is:
SELECT *
FROM myTabl
WHERE created_at >= '2015-03-15 10:25:00' AND
created_at < '2015-03-25 10:30:00'
I am guessing that you don't really want 10 days, five minutes and one second in the interval, but want exactly 10 days and five minutes. In any case, the use of between with dates and datetimes can cause unexpected results, particularly when you do:
where datetime between '2015-03-15' and '2015-03-16'
If you think you are getting two dates, you are wrong. You are getting all date times on the first day plus midnight on the second.
The difference between to datetimes is the number of seconds between them. This seems to work only if the datetimes occur in the same hour.
Why is this?
mysql> update events set created_at = "2011-04-13 15:59:59", fulfilled_at ="2011-04-13 16:00:00" where id = 1;
mysql> select fulfilled_at - created_at, timediff(fulfilled_at, created_at) from events where id = 1;
+---------------------------+------------------------------------+
| fulfilled_at - created_at | timediff(fulfilled_at, created_at) |
+---------------------------+------------------------------------+
| 4041.000000 | 00:00:01 |
+---------------------------+------------------------------------+
I know I should be using timediff, but I'm just curious why I'm seeing this or if it's documented somewhere.
MySQL is just converting strings into numbers as best it can, so that it can do the mathematical operation on them. In this case, its just stripping out all of the non numerical colons, dashes and spaces.
Try this:
SELECT (20110413155959 - 20110413160000) AS dates;
Your dates, without all the stuff that stops them being numbers - the result is -4041
Recall that mysql has two differente kinds of datetime-related substractions: The _SUB suffix is for substracting a date minus an interval, returning a date. The _DIFF suffix is for getting the difference between two dates, returning an interval (BTW, notice that only the first one has an inverse analog: _ADD)
The +/- signs are to be used for the first one (ADD/SUB), hence MYSQL expects an interval as a second argument.
DATE = DATE_ADD(DATE,INTERVAL) Also accepts +
DATE = DATE_SUB(DATE,INTERVAL) Also accepts -
INTERVAL = DATE_DIFF(DATE,DATE )
See doc here, the bit starting from:
Date arithmetic also can be performed using INTERVAL
together with the + or - operator...
Hence, it's incorrect to use the - to take the difference between two dates. Now, MYSQL, when confronted with incorrect outputs, tries to do its best guess (instead of throwing an error), sometimes that goes well, sometimes not.