Add Datatime and Time together and convert it in text - sql

I need to add my work times together and after 10+ hours I have no idea how I should do this.
The tables look like this:
adrID wrk_Start wrk_End wrk_Pause
10 01-04-2020 10:00:00 01-04-2020 18:00:00 00:00:00
10 03-04-2020 10:00:00 03-04-2020 17:30:00 00:30:00
10 06-04-2020 12:00:00 06-04-2020 14:00:00 00:00:00
10 12-04-2020 09:00:00 12-04-2020 16:50:00 00:30:00
The result should be: 23:30 , mine is 5:00:27
The code is working only if I use little intervals like 10.04.2020 - 12.04.2020 and when I use bigger intervals or intervals that are in the future (today we have 17.04 and I use for ex. 10.04 - 20.04) is not working.
DECLARE #FromDate DATETIME = '01-04-2020 10:00:00';
DECLARE #ToDate DATETIME = '20-04-2020 17:00:00';
DECLARE #user INT = 10;
select convert(varchar, DATEADD(ss, sum(isnull(datediff(second, wrk_Start, wrk_End), 0)), 0), 108)
from worktime
where
wrk_adrID = #wrk_Name and
wrk_Start >= #wrk_FromDate and
wrk_End <= #wrk_ToDate

It is normally best to save the dates and time in mysql format, else it gets to much more code:
Your text has to be converted to dates with again get to seconds and finally back to a readable time.
First comes the mysql version, which had tagged false, and lower you find aSQL SERVER version, which is sowhat more complicated
SELECT
SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND,STR_TO_DATE(`wrk_Start`,'%d-%m-%Y %k:%i:%s')
,STR_TO_DATE(`wrk_End`,'%d-%m-%Y %k:%i:%s'))
- TIME_TO_SEC(`wrk_Pause`)))
FROM
worktime;
Schema (MySQL v5.7)
CREATE TABLE worktime (
`wrk_Start` VARCHAR(19),
`wrk_End` VARCHAR(19),
`wrk_Pause` Time
);
INSERT INTO worktime
(`wrk_Start`, `wrk_End`, `wrk_Pause`)
VALUES
('01-04-2020 10:00:00', '01-04-2020 18:00:00', '00:00:00'),
('03-04-2020 10:00:00', '03-04-2020 17:30:00', '00:30:00'),
('06-04-2020 12:00:00', '06-04-2020 14:00:00', '00:00:00'),
('12-04-2020 09:00:00', '12-04-2020 16:50:00', '00:30:00');
Query #1
SELECT
SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND,STR_TO_DATE(`wrk_Start`,'%d-%m-%Y %k:%i:%s')
,STR_TO_DATE(`wrk_End`,'%d-%m-%Y %k:%i:%s'))
- TIME_TO_SEC(`wrk_Pause`)))
FROM
worktime;
| SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND,STR_TO_DATE(`wrk_Start`,'%d-%m-%Y %k:%i:%s')
,STR_TO_DATE(`wrk_End`,'%d-%m-%Y %k:%i:%s'))
- TIME_TO_SEC(`wrk_Pause`))) |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 24:20:00 |
View on DB Fiddle
SQL SERVER
CREATE TABLE worktime (
wrk_Start nvarchar(19),
wrk_End nvarchar(19),
wrk_Pause nvarchar(8)
);
INSERT INTO worktime
(wrk_Start, wrk_End, wrk_Pause)
VALUES
('01-04-2020 10:00:00', '01-04-2020 18:00:00', '00:00:00'),
('03-04-2020 10:00:00', '03-04-2020 17:30:00', '00:30:00'),
('06-04-2020 12:00:00', '06-04-2020 14:00:00', '00:00:00'),
('12-04-2020 09:00:00', '12-04-2020 16:50:00', '00:30:00');
GO
4 rows affected
SELECT
(SUM(DATEDIFF(second,CONVERT(DATETIME,[wrk_Start]),
CONVERT(DATETIME,[wrk_End])) -
DATEDIFF(second,'00:00:00',[wrk_Pause]))) wrktime
FROM
worktime;
GO
| wrktime |
| ------: |
| 87600 |
DECLARE #seconds AS int = 896434;
SELECT CONVERT(varchar, (SUM(DATEDIFF(second,CONVERT(DATETIME,[wrk_Start]),
CONVERT(DATETIME,[wrk_End])) -
DATEDIFF(second,'00:00:00',[wrk_Pause]))) / 86400 ) + ':' + -- Days
CONVERT(varchar, DATEADD(ms, ( (SUM(DATEDIFF(second,CONVERT(DATETIME,[wrk_Start]),
CONVERT(DATETIME,[wrk_End])) -
DATEDIFF(second,'00:00:00',[wrk_Pause]))) % 86400 ) * 1000, 0), 108)
as "orktime"
FROM
worktime;
GO
| orktime |
| :--------- |
| 1:00:20:00 |
db<>fiddle here

First, don't try to convert the value back to a time -- SQL Server does not allow times that exceed 24 hours.
I would go for decimal hours. That would be:
select adrid,
(sum(datediff(second, wrk_start, wrk_end))-
sum(datediff(second, '00:00:00', wrk_pause))
) / (60.0 * 60) as decimal_hours
from worktime
group by adrid;
Here is a db<>fiddle.

Related

Converting date time format

We have data in a Visit_Time column stored in 24Hrs date format as well as 12Hrs.
The data is inserted into a table from a different type of source like MobileApp and Web source etc.
Example:
Create table VisitorDetails
(
Visit_Date Date,
Visit_Time varchar(12)
)
VisitorDetails
----------------------------
Visit_Date Visit_Time
----------------------------
2020-01-01 01:00PM
2020-01-02 17:00
2020-01-03 04:00PM
2020-01-04 20:00
-----------------------------
How to convert Visit_Time Column either in 12 Hrs format or 24 Hrs formate?
Need Result like below
VisitorDetails 12Hrs 24Hrs
---------------------------- --------------
Visit_Date Visit_Time (OR) Visit_Time
---------------------------- --------------
2020-01-01 01:00PM 13:00
2020-01-02 05:00PM 17:00
2020-01-03 04:00PM 16:00
2020-01-04 08:00PM 20:00
----------------------------- --------------
12 hour format
declare #t1 time
declare #t2 time
declare #t3 time
set #t1 = '14:40'
set #t2 = '17:00'
set #t3 = '01:00PM'
select CONVERT(varchar(15),#t1,100)
select CONVERT(varchar(15),#t2,100)
select CONVERT(varchar(15),#t3,100)
When fetching your rows you could do:
SELECT [Visit_Date], LEFT(PARSE([Visit_Time] AS time), 5)
FROM [VisitorDetails]
for a consistent time format.
However, I would strongly recommend returning time values from the db and do the display modification in your app.
Please try below solution:
--24 Hour Format
SELECT CONVERT(VARCHAR(5),CONVERT(DATETIME, '01:00PM', 0), 108)
SELECT CONVERT(VARCHAR(5),CONVERT(DATETIME, '17:00', 0), 108)
--12 Hour Format
SELECT LTRIM(RIGHT(CONVERT(VARCHAR(20), CONVERT(DATETIME, '01:00PM', 0), 100), 7))
SELECT LTRIM(RIGHT(CONVERT(VARCHAR(20), CONVERT(DATETIME, '17:00', 0), 100), 7))
To Store 24 hrs format declare the Column data type as DATETIME Instead of Varchar(12)
DECLARE #T TABLE(
ID INT IDENTITY(1,1),
Visit_DATE_TIME varchar(20))
12 hrs Data insertion:
INSERT INTO #T VALUES('24-MAY-2020 10:30PM')
INSERT INTO #T VALUES('25-MAY-2020 11:30AM')
24 hrs Data insertion:
INSERT INTO #T VALUES('26-MAY-2020 16:30')
INSERT INTO #T VALUES('28-MAY-2020 22:30')
Query
SELECT *, CAST(VISIT_DATE_TIME as DATE) as Visit_Date ,
CAST(VISIT_DATE_TIME as TIME) as Visit_Time_24,
RIGHT(CONVERT(DATETIME,RTRIM(VISIT_DATE_TIME), 109),7) as Visit_Time_12
FROM #T

Time difference between two times in Hours in SQL Server

I need the time difference between two times in Hours. I have the start time and end time as shown below:
Start time | End Time
-----------+----------
23:00:00 | 19:00:00
23:00:00 | 07:00:00
I need the output for first row as 20, for second row 8.
Try this:
Schema:
create table a(Starttime time,Endtime time)
INSERT INTO a VALUES ('23:00:00','19:00:00')
INSERT INTO a VALUES ('09:00:00','19:00:00')
INSERT INTO a VALUES ('23:00:00','07:00:00')
Query:
select Starttime,Endtime,
CASE WHEN datediff(HOUR,Starttime,Endtime)<0 THEN 24+datediff(HOUR,Starttime,Endtime)
ELSE datediff(HOUR,Starttime,Endtime) END Diff
FROM A
Output:
| Starttime | Endtime | Diff |
|------------------|------------------|------|
| 23:00:00.0000000 | 19:00:00.0000000 | 20 |
| 09:00:00.0000000 | 19:00:00.0000000 | 10 |
| 23:00:00.0000000 | 07:00:00.0000000 | 8 |
Use DATEDIFF:
SELECT
start_time,
end_time,
24 + DATEDIFF(HOUR, start_time, end_time) AS diff_in_hours
FROM yourTable;
Demo
Query as per your requirement, just put your table name at the place of "YourTable"
SELECT Starttime
,Endtime
,CASE
WHEN DATEDIFF(HOUR, Starttime, Endtime) < 0
THEN 24 + DATEDIFF(HOUR, Starttime, Endtime)
ELSE DATEDIFF(HOUR, Starttime, Endtime)
END Time_Difference
FROM YourTable
Use select case
select case when start_time > end_time
then datediff(hour, start_time , dateadd(hh, 24, end_Time))
else datediff(hh, start_time , end_Time) end

know in which interval of dates of 15 minutes is a date SQL SERVER

sql fiddle example
I have this table structure :
CREATE TABLE TIMETABLE
([ID] int, [Name] varchar(50), [StartDate] datetime, [EndDate] datetime)
;
INSERT INTO TIMETABLE
([ID], [Name], [StartDate], [EndDate])
VALUES
(1, 'John', '2017-01-29 16:00:00.000', '2017-01-29 16:12:00.000'),
(2, 'Mario', '2017-01-29 16:17:00.000', '2017-01-29 16:29:00.000'),
(3, 'Kate', '2017-01-15 10:35:00.000', '2017-01-15 10:40:00.000'),
(4, 'Maria', '2017-01-15 10:17:00.000', '2017-01-15 10:27:00.000'),
(5, 'Oliver', '2017-01-15 13:46:00.000', '2017-01-29 14:00:00.000')
;
And The result for this :
select * from TIMETABLE
ID Name StartDate EndDate
1 John 2017-01-29T16:00:00Z 2017-01-29T16:12:00Z
2 Mario 2017-01-29T16:17:00Z 2017-01-29T16:29:00Z
3 Kate 2017-01-15T10:35:00Z 2017-01-15T10:40:00Z
4 Maria 2017-01-15T10:17:00Z 2017-01-15T10:27:00Z
5 Oliver 2017-01-15T13:46:00Z 2017-01-29T14:00:00Z
I want to know with a range from 15 mins in wich range is the date, for example:
ID Name StartDate EndDate HourRangeTime
1 John 2017-01-29T16:00:00Z 2017-01-29T16:12:00Z 16:00
In the example the startdate and the enddate is in the range between 16:00 and 16:12 is in the range 16:00
The result it should be like this:
ID Name StartDate EndDate HourRangeTime
1 John 2017-01-29T16:00:00Z 2017-01-29T16:12:00Z 16:00
2 Mario 2017-01-29T16:17:00Z 2017-01-29T16:29:00Z 16:15
3 Kate 2017-01-15T10:35:00Z 2017-01-15T10:40:00Z 10:30
4 Maria 2017-01-15T10:17:00Z 2017-01-15T10:27:00Z 10:15
5 Oliver 2017-01-15T13:46:00Z 2017-01-29T14:00:00Z 13:45
How can I fill the column HourRangeTime, take dates and see what range does it belong to?
Your seem focused on the StartDate.
A relatively general way to do this is to convert this to minutes and then truncate the minutes to the nearest 15 minutes. Here is code:
select cast(dateadd(minute,
15 * (datediff(minute, 0,
cast(StartDate as time)
) / 15
), 0
) as time)
This returns the result as a time.
You can get difference and process future.
SELECT StartTime, EndTime, DATEDIFF(MINUTE, StartTime , EndTime) AS MinuteDiff
FROM TIMETABLE
You can try this for your desired output:
SELECT
CONCAT(DATEPART(hh,StartDate), ':',
CASE
WHEN DATEPART(MINUTE,StartDate) BETWEEN 0 AND 14 THEN '00'
WHEN DATEPART(MINUTE,StartDate) BETWEEN 15 AND 29 THEN '15'
WHEN DATEPART(MINUTE,StartDate) BETWEEN 30 AND 44 THEN '30'
WHEN DATEPART(MINUTE,StartDate) BETWEEN 45 AND 59 THEN '45'
ELSE '00'
END) AS HourRangeTime
FROM TIMETABLE
OUTPUT:
HourRangeTime
-------------
16:00
16:15
10:30
10:15
13:45
You can use this.
SELECT *,
CONVERT(VARCHAR,DATEPART(HOUR, [StartDate]))
+ ':'
+ RIGHT(CONVERT(VARCHAR,(DATEPART(MINUTE, [StartDate]) / 15) * 15)+'0',2) HourRangeTime FROM TIMETABLE

Calculate total time worked in a day with multiple stops and starts

I can use DATEDIFF to find the difference between one set of dates like this
DATEDIFF(MINUTE, #startdate, #enddate)
but how would I find the total time span between multiple sets of dates? I don't know how many sets (stops and starts) I will have.
The data is on multiple rows with start and stops.
ID TimeStamp StartOrStop TimeCode
----------------------------------------------------------------
1 2017-01-01 07:00:00 Start 1
2 2017-01-01 08:15:00 Stop 2
3 2017-01-01 10:00:00 Start 1
4 2017-01-01 11:00:00 Stop 2
5 2017-01-01 10:30:00 Start 1
6 2017-01-01 12:00:00 Stop 2
This code would work assuming that your table only store data from one person, and they should be of the order Start/Stop/Start/Stop
WITH StartTime AS (
SELECT
TimeStamp
, ROW_NUMBER() PARTITION BY (ORDER BY TimeStamp) RowNum
FROM
<<table>>
WHERE
TimeCode = 1
), StopTime AS (
SELECT
TimeStamp
, ROW_NUMBER() PARTITION BY (ORDER BY TimeStamp) RowNum
FROM
<<table>>
WHERE
TimeCode = 2
)
SELECT
SUM (DATEDIFF( MINUTE, StartTime.TimeStamp, StopTime.TimeStamp )) As TotalTime
FROM
StartTime
JOIN StopTime ON StartTime.RowNum = StopTime.RowNum
This will work if your starts and stops are reliable. Your sample has two starts in order - 10:00 and 10:30 starts. I assume in production you will have an employee id to group on, so I added this to the sample data in place of the identity column.
Also in production, the CTE sets will be reduced by using a parameter on date. If there are overnight shifts, you would want your stops CTE to use dateadd(day, 1, #startDate) as your upper bound when retrieving end date.
Set up sample:
declare #temp table (
EmpId int,
TimeStamp datetime,
StartOrStop varchar(55),
TimeCode int
);
insert into #temp
values
(1, '2017-01-01 07:00:00', 'Start', 1),
(1, '2017-01-01 08:15:00', 'Stop', 2),
(1, '2017-01-01 10:00:00', 'Start', 1),
(1, '2017-01-01 11:00:00', 'Stop', 2),
(2, '2017-01-01 10:30:00', 'Start', 1),
(2, '2017-01-01 12:00:00', 'Stop', 2)
Query:
;with starts as (
select t.EmpId,
t.TimeStamp as StartTime,
row_number() over (partition by t.EmpId order by t.TimeStamp asc) as rn
from #temp t
where Timecode = 1 --Start time code?
),
stops as (
select t.EmpId,
t.TimeStamp as EndTime,
row_number() over (partition by t.EmpId order by t.TimeStamp asc) as rn
from #temp t
where Timecode = 2 --Stop time code?
)
select cast(min(sub.StartTime) as date) as WorkDay,
sub.EmpId as Employee,
min(sub.StartTime) as ClockIn,
min(sub.EndTime) as ClockOut,
sum(sub.MinutesWorked) as MinutesWorked
from
(
select strt.EmpId,
strt.StartTime,
stp.EndTime,
datediff(minute, strt.StartTime, stp.EndTime) as MinutesWorked
from starts strt
inner join stops stp
on strt.EmpId = stp.EmpId
and strt.rn = stp.rn
)sub
group by sub.EmpId
This works assuming your table has an incremental ID and interleaving start/stop records
--Data sample as provided
declare #temp table (
Id int,
TimeStamp datetime,
StartOrStop varchar(55),
TimeCode int
);
insert into #temp
values
(1, '2017-01-01 07:00:00', 'Start', 1),
(2, '2017-01-01 08:15:00', 'Stop', 2),
(3, '2017-01-01 10:00:00', 'Start', 1),
(4, '2017-01-01 11:00:00', 'Stop', 2),
(5, '2017-01-01 10:30:00', 'Start', 1),
(6, '2017-01-01 12:00:00', 'Stop', 2)
--let's see every pair start/stop and discard stop/start
select start.timestamp start, stop.timestamp stop,
datediff(mi,start.timestamp,stop.timestamp) minutes
from #temp start inner join #temp stop
on start.id+1= stop.id and start.timecode=1
--Sum all for required result
select sum(datediff(mi,start.timestamp,stop.timestamp) ) totalMinutes
from #temp start inner join #temp stop
on start.id+1= stop.id and start.timecode=1
Results
+-------------------------+-------------------------+---------+
| start | stop | minutes |
+-------------------------+-------------------------+---------+
| 2017-01-01 07:00:00.000 | 2017-01-01 08:15:00.000 | 75 |
| 2017-01-01 10:00:00.000 | 2017-01-01 11:00:00.000 | 60 |
| 2017-01-01 10:30:00.000 | 2017-01-01 12:00:00.000 | 90 |
+-------------------------+-------------------------+---------+
+--------------+
| totalMinutes |
+--------------+
| 225 |
+--------------+
Maybe the tricky part is the join clause. We need to join #table with itself by deferring 1 ID. Here is where on start.id+1= stop.id did its work.
In the other hand, for excluding stop/start couple we use start.timecode=1. In case we don't have a column with this information, something like stop.id%2=0 works just fine.

SQL Sum duration by hour and day

I am trying to write a query that will convert a duration field into seconds and then sum the durations based on what time and day it is.
The duration is the amount of time that the "event" was running during the hour of the end date.
I have this:
Description | Start Date | End Date | Duration
---------------------------------------------------------------------------
ABC | 2015-08-17 10:30:30.000 | 2015-08-17 11:59:59.000 | 0 00:59:59.0
ABC | 2015-08-18 11:00:00.000 | 2015-08-18 11:30:00.000 | 0 00:30:00.0
DEF | 2015-08-17 08:25:00.000 | 2015-08-17 10:30:00.000 | 0 00:30::00.0
ABC | 2015-08-18 11:30:00.000 | 2015-08-18 11:59:59.000 | 0 00:29:59.0
And I'm trying to get something like this:
Description | Date | Hour | Duration
-------------------------------------------
ABC | 2015-08-17 | 11 | 3575
ABC | 2015-08-18 | 11 | 3575
DEF | 2015-08-17 | 10 | 1800
This is the query I have wrote:
SELECT Description,
DATEPART(HOUR, EndDT), SUM(DATEPART(SECOND, CONVERT(TIME, RIGHT(Duration, LEN(Duration) -2))) +
60 * DATEPART(MINUTE, CONVERT(TIME, RIGHT(Duration, LEN(Duration) - 2))) +
3600 * DATEPART(HOUR, CONVERT(TIME, RIGHT(Duration, LEN(Duration) - 2))))
FROM table
GROUP BY Description,
DATEPART(HOUR, EndDT),
DATEADD(d, 0, DATEDIFF(d, 0, EndDT));
This query doesn't seem to be taking days into consideration like I thought it would and I have no idea how fix it.
I am getting something like this:
Description | Hour | Duration
------------------------------
ABC | 11 | 7150
DEF | 10 | 1800
I also realise that I haven't got the date in the select statement at the moment, but that can be added later.
If you GROUP your data by EndDT date part only, you get what you need:
WITH T AS (
SELECT *
FROM (VALUES('ABC', CAST('2015-08-17 10:30:30.000' AS DATETIME), CAST('2015-08-17 11:59:59.000' AS DATETIME), '0 00:59:59.0'),
('ABC', CAST('2015-08-18 11:00:00.000' AS DATETIME), CAST('2015-08-18 11:30:00.000' AS DATETIME), '0 00:30:00.0'),
('DEF', CAST('2015-08-17 08:25:00.000' AS DATETIME), CAST('2015-08-17 10:30:00.000' AS DATETIME), '0 00:30:00.0'),
('ABC', CAST('2015-08-18 11:30:00.000' AS DATETIME), CAST('2015-08-18 11:59:59.000' AS DATETIME), '0 00:29:59.0'))
AS V(Description, StartDT, EndDT, Duration)
)
SELECT Description ,
CAST(EndDT AS DATE),
DATEPART(HOUR, EndDT) ,
SUM(DATEPART(SECOND, CONVERT(TIME, RIGHT(Duration, LEN(Duration) - 2)))
+ 60 * DATEPART(MINUTE,CONVERT(TIME, RIGHT(Duration, LEN(Duration) - 2)))
+ 3600 * DATEPART(HOUR, CONVERT(TIME, RIGHT(Duration, LEN(Duration) - 2))))
FROM T
GROUP BY
Description ,
CAST(EndDT AS DATE),
DATEPART(HOUR, EndDT)
For this i am getting:
ABC 2015-08-17 11 3599
ABC 2015-08-18 11 3599
DEF 2015-08-17 10 1800
You can ignore the CTE that holds data from the example above, just added it to provide a working example.
This gives you how many hours and seconds each event was running for each day.
SELECT Description,
DATEDIFF(s,MIN([Start Date]), MAX([End Date]))/60/60 AS Hour,
DATEDIFF(s,MIN([Start Date]), MAX([End Date])) AS Duration
FROM yourtable
GROUP BY Description, DAY([Start Date])
OUTPUT
Description Hour Duration
ABC 1 5369
DEF 2 7500
ABC 0 3599
SQL Fiddle: http://sqlfiddle.com/#!3/935c7/15/0