Calculating time difference before 6am and after 10pm in MySQL - mysql

I have one question regarding MySQL date / time functions. For now, I have query which looks like this:
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(sum)))
FROM workingtime
WHERE user='magdalena'
AND type='work'
AND start BETWEEN '2014-03-01' AND '2014-03-12'
AND completed=1
So in my database there are 2 columns with timestamps, first one is "start", second one is "end". What I would like to execute in sigle query is this: I would like to have returned how much is the time difference between start and 6am + how much is the time difference between 10pm and end (with option for nex day...). I need this for night shift hours - so I need sum of nightshift hours together as a result.
Example:
start = 2014-02-26 03:30:00
end = 2014-02-26 12:16:59
I would like to get difference between start and 6am and 10pm and end.
In this case: difference between 3:30:00 and 6:00:00 is 2:30:00. Difference between 10pm and end is nothing in this case, because end time is not over 10pm at all. So the result in this case will be 2:50:00. That is the output I would like to get.
Is this possible only with MySQL?
Thank you guys, I appreciate it.

Use can use the TIMEDIFF function, like this:
select
CONCAT(HOUR(TIMEDIFF(starttime, CONCAT(DATE(starttime),' 06:00:00'))), ':', MINUTE(TIMEDIFF(starttime, CONCAT(DATE(starttime),' 06:00:00')))) AS startdiff,
CONCAT(HOUR(TIMEDIFF(CONCAT(DATE(endtime),' 22:00:00'), endtime)), ':', MINUTE(TIMEDIFF(CONCAT(DATE(endtime),' 22:00:00'), endtime))) AS enddiff
from workingtime
Working demo: http://sqlfiddle.com/#!2/fc621/1
I was not able to understand the following part of your question: "with option for next day"

Related

Sql to get number of hours per user per day

A table 'Log' has the below columns:
SystemName
User
Datetime - it's a timestamp
Status - has the values Start or Stop.
I need to write a query which will give me :
Number of hours spent per user per day on system X.
Please see example data below:
X, Amit, 05/01/2019 08:45:00, Start
X, Amit, 05/03/2019 13:25:00, Stop
X, Dave, 05/01/2019 09:10:35, Start
X, Dave, 05/01/2019 17:35:42, Stop
Output:
Amit,05/01/2019, 15h
Amit,05/02/2019, 24h
Amit,05/03/2019, 9h
Dave,05/01/2019, 8h
My approach till now :
I was thinking I could use lead or lag to get the consecutive times in the same row. But in the case of user Amit that spans across multiple days. Also there could be a user who has started and stopped multiple times on the same day. Even if I do that how could I generate hours for the dates amidst the range. Can you please help me.
This should work. You will only get Hours spent if both Start and Stop status exists for a user in a single day.
SELECT SystemName,[user],
CONVERT(varchar, CAST(Datetime AS DATETIME), 1) Datetime,
DATEDIFF
(
HH,
MAX(CASE WHEN Ststus = 'Start' THEN [Datetime] ELSE NULL END ),
MAX(CASE WHEN Ststus = 'Stop' THEN Datetime ELSE NULL END )
)HourSpent
FROM your_table A
GROUP BY SystemName,[User],
CONVERT(varchar, CAST(Datetime AS DATETIME), 1)
Since the output consists of one row per User + Day, then you would need to JOIN the data to a calendar table of dates.
You would need a way to extract the Start and Stop timestamp pairs for a given user, join it to the calendar table, then count the number of hours on that day that are between the start and stop times. (The hour count could be use a User Defined Function.
That's pretty complex. Frankly, I would rather write a Python program to parse the data rather than doing it via SQL. It would be very simple:
Read start line
Read end line
Loop through days, outputting hours per day (quite simple in Python)
Sometimes the best hammer is a spanner. (Translation: Sometimes a different tool is better.)

get range between two timestamp

I like to get the total hours in between two timestamp.
Take a look at my code
$sql="UPDATE timekeeping SET end= timestamp(NOW()),totalrange = ((end- begin) - 1)
WHERE end IS NULL and fullname = '$whoareyou[fullname]'";
but in this code "totalhours = ((end- begin) - 1)" is wrong i feel it :)
I want this to show something like this
2014-05-07 02:00:38.000000 - 2014-05-07 06:00:38.000000 = 4
and something like this
2014-05-07 02:00:38.000000 - 2014-05-07 06:30:38.000000 = 4.30
but i do not know where or what to do.
Please help anyone. I have done my part in researching and found no suitable answer which I can understand since this was my first time to use php.
The following SQL query should do the trick:
SELECT TIMESTAMPDIFF(HOUR, '2012-06-06 13:13:55', '2012-06-06 15:20:18');
Replace the second argument with the date they last logged in and the third argument with the date of their current login.
This will return an integer equal to the hours between the first time stamp and the second time stamp.
EDIT: If you wish to get also the minutes, then replace 'HOUR' with 'MINUTE' and do some math to get the decimal value of Hours.Minutes.

MySQL time between returning false and it should be true

SELECT *
FROM tablename
WHERE
MAKETIME(3,0,0) BETWEEN MAKETIME(23,0,0) AND MAKETIME(5,0,0)
is returning nothing And 3:00 is between 23:00 AND 5:00 time. Why is that can anyone explain me how to solve this problem?
It's unclear what you're actually trying to do here, because even if 3 were between 5 and 23 your query would simply return every record in the table.
SELECT MAKETIME(3,0,0) BETWEEN MAKETIME(5,0,0) AND MAKETIME(23,0,0)
Returns 0, because 3 is not between 5 and 23.
SELECT MAKETIME(5,0,0) BETWEEN MAKETIME(3,0,0) AND MAKETIME(23,0,0)
Returns 1, because 5 is between 3 and 23.
Demo: SQL Fiddle
Presumably you're trying to wrap into the previous day, in which case you can directly compare datetime values, but it's unclear given your question what fields/datatypes you're actually working with.
Update:
Based on your comment, I think you want 2 comparisons. 3 is not between 5 and 23, because time doesn't wrap across days. But if you only care about the time portion you can handle it like this:
SELECT *
FROM tablename
WHERE YourTime BETWEEN MAKETIME(23,0,0) AND MAKETIME(23,59,59)
OR YourTime BETWEEN MAKETIME(0,0,0) AND MAKETIME(5,0,0)
Remember that BETWEEN is inclusive, so if 5am is your cutoff time you may want it to be MAKETIME(4,59,59) so it includes 4:59 but not 5:00
Function MAKETIME returns a time value calculated from the hour, minute, and second arguments:
mysql> SELECT MAKETIME(3,0,0),MAKETIME(23,0,0),MAKETIME(5,0,0)
-> '03:00:00', '23:00:00', '05:00:00'
and, of course, 3 is not BETWEEN 23 AND 5 and it will return false. But yes, 3AM actually is between 11PM and 5AM, so how could you solve this?
Let's consider 23 as your START_TIME, and 5 as your END_TIME.
Since START_TIME has to happen before END_TIME, if this is not the case (23>5) that means that the interval rolls over the next day.
I would try with a query like this:
SELECT *
FROM yourtable
WHERE
(MAKETIME(START_TIME,0,0)<=MAKETIME(END_TIME,0,0) AND MAKETIME(3,0,0) BETWEEN MAKETIME(START_TIME,0,0) AND MAKETIME(END_TIME,0,0))
OR
(MAKETIME(START_TIME,0,0)>MAKETIME(END_TIME,0,0) AND NOT (MAKETIME(3,0,0) BETWEEN MAKETIME(START_TIME,0,0) AND MAKETIME(END_TIME,0,0)))

How to update timestamp column moving date forward

what I am looking for is some help with a query.
I have a MySql field with unixtime in it representing a date in each of the next few dozen months. I have to move the dates forward to the first day of the next month for each entry in the table.
The dates are all the 20th of each month, and so I want to move June 20 to July 1, July 20 to August 1, and so on. I can't just add 11 days, because that wouldn't be the first day of the next month when considering months with 31 days and February.
I have been playing with ideas like this:
update table set column = UNIX_TIMESTAMP(column + MONTH(column)+1,DAY(1)) where index_column = '1234'
but I am pretty sure that won't work. I could use something like this to convert it, then try to convert it back:
update table set column = DATEFORMAT(column,'%Y-$c-%d %H:%i:%s') where index_column == '1234'
I still think there has to be a better way. Frankly, I would update the few dozen manually, but I know this will come up frequently, and don't want to have to do it manually every time.
I prefer not to use code, but would instead like to just do it directly into MySql. I hope there is someone out there that can help me figure this out.
Thank you in advance.
Maybe something like this Works:
update table set column = UNIX_TIMESTAMP(LAST_DAY(FROM_UNIXTIME(column)) + INTERVAL 1 DAY) where index_column = '1234'
Reference: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_last-day
Does ADDDATE do it for you? Or do you need something more?

sql Date in month time span

I have entries in my Table like
uid / start / end / value
I now want to select all entries which lie in a specific month. So if the user chooses "June", I want to get all Entries than are available in June. The start and end are saved as timestamp (cant change that). I found somthing like:
WHERE month(start)=5
This does work, but unfortunately it only gives me the entries that start in June. I Can of course add the same for the end, but this would still not help if an entry starts in may and ends in july. I could of course calculate timestamps and compare directly, but i want to select this for june of any year - not just one specific. I was thinking of something like:
WHERE month(start) <= 5 && month(end) >= 5
which would work fine with timestamps, but obviously this has a problem with year-breaks.
Is there a nice solution to do this without calculating all timestamps for the following years and creating a sick big query?
Ok i figured this out:
WHERE month(start)=5
OR month(end)=5
OR ( month(start)<=5 AND month(end) >= 5)
OR ( month(start)<=5 AND year(start)<year(end))
OR ( month(end)>=5 AND year(start)<year(end))
I think it is correct and works fine.
It looks like it should work, but it's quite convoluted, and I'm pretty sure the use of the month function means you won't be hitting any indices.
You can also rephrase it as:
where start <= 1 Jun 2011
and end >= 1 Jul 2011