Storing a duration in mysql - mysql

I need to store durations such as the following in mysql:
- 30 seconds
- 20 minutes, 12 seconds
- 1 month
What would be the best way to store this, as the definition of a month can't be reduced, for example, to a number of seconds. My first thought was to store each increment separate, for example:
- num_seconds
- num_minutes
- num_hours
- num_days
- num_months
This could store the above, but I was hoping there was a more direct and less verbose way of doing this.

My first option would be to store duration as a number of seconds with datatype INT. This will make computation and comparison operations fast and clean. Also you can easily compute the duration between two datetime values, by substracting their Unix timestamp. When you need to display the values, you can use mysql sec_to_time function :
However if you are looking to manipulate big durations (months, years), this will not work. In that case I would fallback on a VARCHAR column with iso8601 duration format, like P3Y6M4DT12H30M5S for 3 years, 6 months, 4 days, 12 hours, 30 minutes and 5 seconds. It is a well known format that is supported by many applications (but will be more tedious to manipulate).

Store your intervals for years to months as an integer counting the number of months (12 months = 1 year) and your intervals for days to seconds as an integer of number of seconds.
You can then use the DATE_ADD function to figure out your dates. Here's a SQL Fiddle example showing storing intervals as months and seconds, and adding them to a fixed date:
MySQL 5.6 Schema Setup:
create table mytab (dt date);
insert into mytab values (date '2018-01-01');
create table intervals (months int, seconds int);
insert into intervals values (13, 3661), (-13, -3661);
Query 1:
select dt
, months
, seconds
, date_add(date_add(dt, interval months month)
, interval seconds second) result
from mytab cross join intervals
Results:
| dt | months | seconds | result |
|------------|--------|---------|----------------------|
| 2018-01-01 | 13 | 3661 | 2019-02-01T01:01:01Z |
| 2018-01-01 | -13 | -3661 | 2016-11-30T22:58:59Z |

Related

In MySql how do I get all rows that have a date of less than or equal to today at 5 am UTC time?

I have a MySql DB that consists of a table that holds all my data. I need to retrieve only those rows that have a startup_date that is less than or equal to today at 5 am UTC time. I tried looking up but it's kind of confusing. Can someone provide me a good, clean way of doing this?
My table is as follows:
tbl_MyData
***********
id name city startup_date
1 test1 New York 2020-01-10 18:19:30
2 test2 Houston 2019-01-30 05:00:00
3 test3 Chicago 2020-02-09 05:00:00
From the above data, my query should return ONLY row id number 2, since that is the only row that satisfies my criteria of startup_date being less than or equal to today at 5 am. Also, I'm not sure if I need to have any kind of UTC functions, since I'm not sure how mysql stores it's date time data.
Use a simple WHERE clause
SELECT t.* FROM mytable WHERE t.startup_date <= DATE_ADD(CURDATE(), INTERVAL 5 HOUR)
The CURDATE() function returns the current date without time (hence today at midnight), and the DATE_ADD() function adds 5 hours to it.
What SELECT statement have you tried also what are the data types for the table? If startup-date is a date type in MySQL then it should just be
SELECT * FROM tbl_MyData WHERE startup_date<=(whatever the value needs to be)

How to get half hour if exist with mysql hour function

I want to get 8:30 hour instead of 8 from below query
HOUR(TIMEDIFF('2018-12-01 07:00:00','2018-12-01 15:30:00')
Mysql hour function only return number of hour not half hour
We can get the difference between two datetime values in SECOND units, using TimeStampDiff() function. Now, we can convert this into Time using Sec_To_time() function.
SELECT SEC_TO_TIME(TIMESTAMPDIFF(SECOND, '2018-12-01 07:00:00','2018-12-01 15:30:00'))
Result
| SEC_TO_TIME(TIMESTAMPDIFF(SECOND, '2018-12-01 07:00:00','2018-12-01 15:30:00')) |
| ------------------------------------------------------------------------------- |
| 08:30:00 |
You may call both HOUR and MINUTE, the latter to get the minute component:
SELECT
HOUR(TIMEDIFF('2018-12-01 07:00:00','2018-12-01 15:30:00')) +
MINUTE(TIMEDIFF('2018-12-01 07:00:00','2018-12-01 15:30:00')) / 60.0 AS hours
FROM yourTable;
This outputs 8.5 for the number of hours.
Another option would be to first convert both timestamps to UNIX timestamps in seconds since epoch. Then convert their difference back to hours:
SELECT
(UNIX_TIMESTAMP('2018-12-01 15:30:00') -
UNIX_TIMESTAMP('2018-12-01 07:00:00')) / 3600.0 AS hours
FROM yourTable;
Demo

Check if a timestamp column value is more than six months old

I have a table t_windows_updates which has two columns ci_id and update_installed_on. Table will be having all the windows updates happened to all the assets in my environment.
Data will be like
ci_id| update_installed_on
1 | 1452364200000
1 | 1453055400000
2 | 1441650600000
2 | 1441650600000
2 | 1441650600000
I want to get all ci_ids for which the latest update didn't happen in the last six months.
My Query is
SELECT t.ci_id FROM `t_windows_update` t
GROUP BY t.ci_id
HAVING MAX(t.update_installed_on)<= (NOW() - INTERVAL 6 MONTH);
It is running but getting wrong results.
Your problem is the date format.
I think this is a unix format in milliseconds. So, this suggests something like:
having max(t.update_installed_on) <= UNIT_TIMESTAMP(CURDATE() - INTERVAL 6 MONTH) * 1000
I realize that the above could have overflow issues with integers, so let's go the other way:
having max(t.update_installed_on) / 1000 <= UNIT_TIMESTAMP(CURDATE() - INTERVAL 6 MONTH)

MySQL: How to convert seconds to mm:ss format?

I want to convert seconds to minute : seconds format in sql select statement.
At the moment I am using:
SELECT SEC_TO_TIME(duration) from messages;
It works perfectly but it gives me this format of time: hh:mm:ss
but I need mm:ss
Is it possible to convert seconds into mm:ss format using sql query?
If the value is less than an hour, then just do:
SELECT RIGHT(SEC_TO_TIME(duration), 5) from messages;
If you might go over an hour, then do the arithmetic:
SELECT CONCAT_WS(':', FLOOR(SEC_TO_TIME(duration) / 60),
SEC_TO_TIME(duration) % 60)
I recently had a similar project where I needed to convert stored seconds to m:ss format. No matter the amount, there needed to be at least one digit representing minutes and two digits representing seconds. The hours placeholder was forbidden, so the minutes value could acceptably go beyond 59 and also contain more than 2 digits. The minute value must not be zero-padded.
This is what I used: (SQLFiddle Demo)
CONCAT(FLOOR(seconds/60), ':', LPAD(MOD(seconds,60), 2, 0)) AS `m:ss`
aka
CONCAT(FLOOR(seconds/60), ':', LPAD(seconds%60, 2, 0)) AS `m:ss`
seconds | m:ss
-----------------
0 | 0:00
1 | 0:01
10 | 0:10
60 | 1:00
61 | 1:01
71 | 1:11
3599 | 59:59
3600 | 60:00
5999 | 99:59
6000 | 100:00
TIME_FORMAT(SEC_TO_TIME(seconds),'%i:%s') was unsuitable because the project specifications did not want the minute portion to be zero-padded. Here is a good post relating to this technique.
There is no single-digit minute option in TIME_FORMAT() or DATE_FORMAT().
If you are using MySQL 8.0+ you can use REGEXP_REPLACE like this to achieve a variable length string similar mickmackusa's answer:
REGEXP_REPLACE(SEC_TO_TIME(duration), '^(0|:)+', '')

Generating a MySQL hourly breakdown from current timestamp

I'm afraid this is probably a very embarrassingly easy question - but my mind is just completely stuck at this hour.
I have a table that stores the number of activities carried out by different people, and the time it took place in.
I want to create a report that accepts the person's name as a parameter, and show the number of activities per hour for that person during each of the previous 24 hours starting from current timestamp (now()).
Right now,
SELECT hour(TimeStamp), activities FROM tbl1
WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 24 HOUR) AND Name = ?
GROUP BY hour(timestamp)
only returns to me those hours when any activity was present. However, I want a complete 24 hour breakdown with zero for when there was no activity.
i.e. I'm getting
Hour | No. of Activities
1 | 34
4 | 22
9 | 86
but I want
Hour | No. of Activities
1 | 34
2 | 0
3 | 0
4 | 22
5 | 0
... etc.
How do I do this?
(The order of hours in the example is irrelevant)
You can create a hourly table, and do a LEFT JOIN
create table hourly
(
/* hour is not a reserved keyword */
hour smallint(2) not null default 0
);
insert into hourly values (0),(1).... until 24
SELECT
hourly.hour,
COALESCE(COUNT(activities),0) AS "No of Activities"
FROM hourly
LEFT JOIN tbl1 ON hourly.hour=hour(tbl1.TimeStamp)
WHERE
tbl1.timestamp>=DATE_SUB(NOW(), INTERVAL 24 HOUR) AND
tbl1.Name=?
GROUP BY hourly.hour
ORDER BY hourly.hour;