I am getting weird results for the datediff function.
It's zero for different and same timestamps?
select datediff('2015-04-25 20:37:45','2015-04-25 05:20:00');
+-------------------------------------------------------+
| datediff('2015-04-25 20:37:45','2015-04-25 05:20:00') |
+-------------------------------------------------------+
| 0 |
+-------------------------------------------------------+
select datediff('2015-04-25 20:37:45','2015-04-25 20:37:45');
+-------------------------------------------------------+
| datediff('2015-04-25 20:37:45','2015-04-25 20:37:45') |
+-------------------------------------------------------+
| 0 |
+-------------------------------------------------------+
datediff will do the calculation on the dates and find the difference in days,
however you can use timestampdiff for different difference like hour,min etc as
mysql> select timestampdiff(hour,'2015-04-25 05:20:00','2015-04-25 20:37:45') as hour;
+------+
| hour |
+------+
| 15 |
+------+
1 row in set (0.00 sec)
If you look at the MySQL Manual:
DATEDIFF
DATEDIFF() returns expr1 − expr2 expressed as a value in days from one date to the other. expr1 and expr2 are date or date-and-time expressions. Only the date parts of the values are used in the calculation
So what you are getting is correct.
If you are looking for time difference, I would suggest looking into TIMEDIFF or TIMESTAMPDIFF.
If you would like to get the difference in minutes, the best way would be TIMESTAMPDIFF.
Here is an example of how you could do it:
SELECT TIMESTAMPDIFF(MINUTE, '2015-04-25 20:37:45','2015-04-25 05:20:00');
+--------------------------------------------------------------------+
| TIMESTAMPDIFF(MINUTE, '2015-04-25 20:37:45','2015-04-25 05:20:00') |
+--------------------------------------------------------------------+
| -917 |
+--------------------------------------------------------------------+
you should use TIMEDIFF() function instead of DATEDIFF if you want to compare two timestamps with difference lower than day. For example:
select TIMEDIFF('2015-04-25 20:37:45','2015-04-25 05:20:00');
or for result in sec:
select TIME_TO_SEC(TIMEDIFF('2015-04-25 20:37:45','2015-04-25 05:20:00'));
For more details:
MySQL: how to get the difference between two timestamps in seconds
hope this helps :)
Related
LEFT or DATE_FORMAT, which is faster to re-format date in SELECT query in mysql?
I'll show an example of this problem.
Info of PERSON table
Column name
Type
NAME
VARCHAR(20)
YEAR
DATETIME
PERSON
NAME
YEAR
Travis
2020-01-01
Sam
2021-01-01
If execute 'SELECT YEAR FROM PERSON' query, can see below result.
YEAR
2020-01-01 00:00:00
2021-01-01 00:00:00
But I want result like below.
YEAR
2020-01-01
2021-01-01
So, I wanted use one of below queries.
SELECT LEFT(YEAR,10) FROM PERSON
SELECT DATE_FORMAT(YEAR, '%Y-%m-%d')
However, I wonder what query perform better.
Please, help me..
Technically, LEFT() is nearly four times faster, based on this test on my M1 Macbook. Your result might vary.
mysql> select benchmark(100000000, left(year, 10)) from person;
+--------------------------------------+
| benchmark(100000000, left(year, 10)) |
+--------------------------------------+
| 0 |
+--------------------------------------+
1 row in set (1.75 sec)
mysql> select benchmark(100000000, date_format(year, '%Y-%m-%d')) from person;
+-----------------------------------------------------+
| benchmark(100000000, date_format(year, '%Y-%m-%d')) |
+-----------------------------------------------------+
| 0 |
+-----------------------------------------------------+
1 row in set (6.81 sec)
But given that I had to execute both expressions 100 million times to observe a significant difference, both of them are so fast that I wouldn't worry about it. It's likely that other parts of the query will be of far greater influence on performance.
Worrying about which of these two functions has better performance is like worrying if it's better to use one finger or two fingers to lift a 100kg barbell.
This question already has answers here:
What is the behavior for the minus operator between two datetimes in MySQL?
(2 answers)
Closed 1 year ago.
I wrote a query like
select endtime - begintime ....
and it looked like the difference in seconds. But it turns out that it is very odd number (both columns of type timestamp, no timezones mentioned).
select timestampdiff(seconds, begintime, endtime)
works.
But I am more than a little curious as to what the subtraction operator does! I could not find any documentation. It is certainly a booby trap for new users.
(And nobody really understand timezones. There is what is stored, vs what is displayed in different time zones, which drivers etc. muck with it, and lots and lots of false information and confusion. I don't know what With Timezone really means, but I only use the one timezone of the server, although my browser is in a different timezone so phpadmin might be lying to me.)
When used as a number, a timestamp like '2021-01-02 03:04:05' will be treated as 20210102030405. You can see this with e.g. select timestamp('2021-01-02 03:04:05')-0;. Subtracting two such "numbers" isn't going to be meaningful, except that the sign of the result will tell you which time was later.
This doesn't apply if you use the special INTERVAL syntax to adjust a timestamp by an interval, e.g. select '2021-01-02 03:04:05' - INTERVAL 1 WEEK;.
Here's a demo:
mysql> create table mytable (endtime datetime, begintime datetime);
Query OK, 0 rows affected (0.05 sec)
mysql> insert into mytable values (now(), '2021-05-01');
mysql> select endtime - begintime from mytable;
+---------------------+
| endtime - begintime |
+---------------------+
| 6011403 |
+---------------------+
What's up with this weird value? Well, when you put datetime values into an integer arithmetic expression, they values are converted to integers, but not in units of seconds. You can also force these values to be integers this way:
mysql> select endtime+0 as e, begintime+0 as b from mytable;
+----------------+----------------+
| e | b |
+----------------+----------------+
| 20210507011403 | 20210501000000 |
+----------------+----------------+
Here we see that the values are integers, but they are based on converting the datetime values to YYYYMMDDHHMMSS format.
Guess what the difference is?
mysql> select e-b from (select endtime+0 as e, begintime+0 as b from mytable) as t;
+---------+
| e-b |
+---------+
| 6011403 |
+---------+
But this is not the actual time difference, because there are not 100 minutes in an hour, 100 hours in a day, etc.
mysql> select timestampdiff(second, begintime, endtime) as timestampdiff from mytable;
+---------------+
| timestampdiff |
+---------------+
| 522843 |
+---------------+
I am trying to convert a TIMESTAMP to the DATETIME, DATE and TIME MySQL types using the FROM_UNIXTIME field. I noticed that the values for TIME and DATETIME fields have different time information on them.
Instead of the insert statement to the table, I am replacing it with a simple select statement that prints the values:
select FROM_UNIXTIME('1468561341') as timestamp_datetime,FROM_UNIXTIME('1468561341','%d/%m/%y') as timestamp_date, FROM_UNIXTIME('1468561341','%h:%m:%s %p') as timestamp_time
The results look like this:
timestamp_datetime: 2016-07-15 05:42:21.000000
timestamp_date 15/07/16
timestamp_time 05:07:21 AM
How can I get consistent time value in both these columns?
the issue is with letter m
it should be i
mysql> select FROM_UNIXTIME(1468561341) as timestamp_datetime,FROM_UNIXTIME(1468561341,'%d/%m/%y') as timestamp_date, FROM_UNIXTIME(1468561341,'%h:%i:%s %p') as timestamp_time;
+---------------------+----------------+----------------+
| timestamp_datetime | timestamp_date | timestamp_time |
+---------------------+----------------+----------------+
| 2016-07-15 05:42:21 | 15/07/16 | 05:42:21 AM |
+---------------------+----------------+----------------+
1 row in set (0.05 sec)
Your problem is that in your FROM_UNIXTIME you are essentially telling it to do
hours-months-seconds -AM/PM
But you want
hours-minutes-seconds -AM/PM
So change it to
FROM_UNIXTIME(1468561341,'%h:%i:%s %p')
instead.
Reference guide for all the time parameters and usage of time functions in MySQL here: https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html
Here's my MySQL query:
SELECT YEARWEEK(paid) AS yweek,
STR_TO_DATE(YEARWEEK(paid), '%X%V') AS date,
COUNT(*) AS cnt
FROM members
WHERE YEARWEEK(paid) >= YEARWEEK(curdate()) - 52
GROUP BY yweek
Here is the result:
yweek date cnt
201429 0000-00-00 201
201430 0000-00-00 435
201431 0000-00-00 333
201432 0000-00-00 470
201433 0000-00-00 534
The yweek column and cnt column are fine, but the date column is always 0000-00-00. The paid column in the members table is of the format (PHP) date("Y-m-d H:i:s"), is of the column type TIMESTAMP, and here's an example: 2014-06-26 00:32:02.
I have tried replacing YEARWEEK(paid) with CAST(YEARWEEK(paid) AS CHAR(7)), but that changes nothing.
Does the fact that I'm using a TIMESTAMP cause STR_TO_DATE() to give all zeros? I want to have the first date of the week along with cnt, the number of registrations in that week.
Problem is: you cannot get a date from a yearweek: there's 7 options, which one do you want?
mysql> SELECT STR_TO_DATE('201429', '%X%V');
+-------------------------------+
| STR_TO_DATE('201429', '%X%V') |
+-------------------------------+
| 0000-00-00 |
+-------------------------------+
1 row in set (0.00 sec)
If we add a 'day of the week' (%w) to it, it magically begins to worK:
mysql> SELECT STR_TO_DATE('2014290', '%X%V%w');
+----------------------------------+
| STR_TO_DATE('2014290', '%X%V%w') |
+----------------------------------+
| 2014-07-20 |
+----------------------------------+
1 row in set (0.00 sec)
But: this means you have to choose the day of the week you want statically, because the original date is no longer in a yearweek.
Of course, in this case, you might as well have done this:
SELECT
YEARWEEK(paid) AS yweek,
DATE(paid) AS date,
COUNT(*) AS cnt
....
... but I assumed this was just an illustration of the problem getting a date of a yearweek string. If not, then this second solution will just work for you.
I am trying to query a table that is setup with id, startDateTime, endDateTime. Let's say row 1 looks like this:
id startDateTime endDateTime
100 2/9/2012 20:55 3/21/2012 10:43
I need to query the above such that I get a distinct count of all the days in the above range.
My expected result would be in the above 42 as there are 42 unique calendar days from 2/9 through 3/21. Datediff because it looks at the time piece gives me 41 days. I have tried various iterations of datediff and timediff trying to get this to work but can't find anything that works in all scenarios. Any suggestions as to how this can be done in SQL?
I started with a query as shown below:
SELECT ConditionStatus.ID,
SUM((DATEDIFF(ConditionStatus.endDate,ConditionStatus.startDate))) AS Duration
WHERE ID = 100
My query returns a Duration of 41 which is technically accurate but I need to condition such that every date in the range of dates gets a count of 1
I am trying to mimic some logic we use on our datawarehouse where we persist a count of 1 for each date for which there was activity.
Thanks,
Bob
The basic answer is that you can use DATEDIFF() and add 1 because you want to include the current day.
For example:
mysql> select datediff(current_date(),current_date()) + 1;
+---------------------------------------------+
| datediff(current_date(),current_date()) + 1 |
+---------------------------------------------+
| 1 |
+---------------------------------------------+
1 row in set (0.00 sec)
Expanding on your original example, you can convert the strings to datetimes, then discard the time component, then calculate the inclusive date count with a query like this:
mysql> SELECT ABS(DATEDIFF(DATE(STR_TO_DATE('2/9/2012 20:55','%m/%d/%Y %H:%i')),
-> DATE(STR_TO_DATE('3/21/2012 10:43','%m/%d/%Y %H:%i')))) + 1 as days_in_range;
+---------------+
| days_in_range |
+---------------+
| 42 |
+---------------+
1 row in set (0.00 sec)
mysql> SELECT ABS(DATEDIFF(DATE(STR_TO_DATE('3/21/2012 10:43','%m/%d/%Y %H:%i')),
-> DATE(STR_TO_DATE('2/9/2012 20:55','%m/%d/%Y %H:%i')))) + 1 as days_in_range;
+---------------+
| days_in_range |
+---------------+
| 42 |
+---------------+
1 row in set (0.00 sec)
See this answer - How do I select the number of distinct days in a date range?
Take a look before you use #Ike's answer. If you add +1, you will get one too many in instances where the time value is 00:00:00.
select datediff(days, '2/9/2012 20:55', '3/21/2012 10:43') returns 41
select datediff(days, '2/9/2012 20:55', '3/21/2012 10:43') + 1 returns 42
This is where that breaks -
select datediff(days, '2/9/2012 20:55', '3/21/2012 00:00:00') + 1 returns 42
That's the wrong answer. It should not include the last day.
Here's the workaround -
datediff(days, '2/9/2012 20:55', dateadd(seconds, -1, '3/21/2012 00:00:00') + 1