How to sum up time field in SQL Server - sql

I have a column called "WrkHrs" and the data type is time(hh:mm:ss). I want to sum up the working hours for employees. But since it's time data type sql server doesn't let me use like sum(columnname).
How can I sum up the time data type fieled in sql query?

SELECT EmployeeID, minutes_worked = SUM(DATEDIFF(MINUTE, '0:00:00', WrkHrs))
FROM dbo.table
-- WHERE ...
GROUP BY EmployeeID;
You can format it pretty on the front end. Or in T-SQL:
;WITH w(e, mw) AS
(
SELECT EmployeeID, SUM(DATEDIFF(MINUTE, '0:00:00', WrkHrs))
FROM dbo.table
-- WHERE ...
GROUP BY EmployeeID
)
SELECT EmployeeID = e,
WrkHrs = RTRIM(mw/60) + ':' + RIGHT('0' + RTRIM(mw%60),2)
FROM w;
However, you're using the wrong data type. TIME is used to indicate a point in time, not an interval or duration. Wouldn't it make sense to store their work hours in two distinct columns, StartTime and EndTime?

In order to sum up the working hours for an employee you can calculate the difference between the shift start time and end time in minutes and convert it to readable format as following:
DECLARE #StartTime datetime = '08:00'
DECLARE #EndTime datetime = '10:47'
DECLARE #durMinutes int
DECLARE #duration nvarchar(5)
SET #durMinutes = DATEDIFF(MINUTE, #StartTime, #EndTime)
SET #duration =
(SELECT RIGHT('00' + CAST((#durMinutes / 60) AS VARCHAR(2)),2) + ':' +
RIGHT('00' + CAST((#durMinutes % 60) AS VARCHAR(2)), 2))
SELECT #duration
The result : 02:47
two hours and 47 minutes

select DATEDIFF(MINUTE, '0:00:00', '00:02:08')
results in :- 2
select DATEDIFF(SECOND, '0:00:00', '00:02:08')
results in :- 128
Using seconds gives a better answer.
So I think the answer can be
SELECT
EmployeeId
, seconds_worked = SUM (DATEDIFF (SECOND, '0:00:00', WrkHrs))
FROM
tbl_employee
GROUP BY
EmployeeId;

DECLARE #Tab TABLE
(
data CHAR(5)
)
INSERT #Tab
SELECT '25:30' UNION ALL
SELECT '31:45' UNION ALL
SELECT '16:00'
SELECT STUFF(CONVERT(CHAR(8), DATEADD(SECOND, theHours + theMinutes,
'19000101'), 8), 1, 2, CAST((theHours + theMinutes) / 3600 AS VARCHAR(12)))
FROM (
SELECT ABS(SUM(CASE CHARINDEX(':', data) WHEN 0 THEN 0 ELSE 3600 *
LEFT(data, CHARINDEX(':', data) - 1) END)) AS theHours,
ABS(SUM(CASE CHARINDEX(':', data) WHEN 0 THEN 0 ELSE 60 *
SUBSTRING(data, CHARINDEX(':', data) + 1, 2) END)) AS theMinutes
FROM #Tab
) AS d

For MS SQL Server, when your WorkingTime is stored as a time, or a varchar in order to sum it up you should consider that:
1) Time format is not supporting sum, so you need to parse it
2) 23:59:59.9999999 is the maximum value for the time.
So, the code that will work to get you the total number of WorkingHours:WorkingMinutes:WorkingSeconds would be the following:
SELECT
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) / 3600),'00') as varchar(max)) + ':' +
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) % 3600 / 60),'00') as varchar(max)) + ':' +
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) % 3600 % 60),'00') as varchar(max)) as WorkingTimeSum
FROM TableName

It must be as simple as that.
Steps
convert time to seconds
sum the RESULT
convert the sum to time
Eg:
take a case you might want to sum the following time:
| present_hours |
|-----------------|
| 00:01:20.000000 |
|-----------------|
| 00:01:13.000000 |
|-----------------|
| 00:01:45.000000 |
|-----------------|
| 00:01:03.000000 |
|-----------------|
| 00:01:10.000000 |
|-----------------|
| 00:00:56.000000 |
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(present_hours))) as total_present_hours FROM time_booking;

Related

How to calculate the sum of time with SQL SERVER? [duplicate]

I have a column called "WrkHrs" and the data type is time(hh:mm:ss). I want to sum up the working hours for employees. But since it's time data type sql server doesn't let me use like sum(columnname).
How can I sum up the time data type fieled in sql query?
SELECT EmployeeID, minutes_worked = SUM(DATEDIFF(MINUTE, '0:00:00', WrkHrs))
FROM dbo.table
-- WHERE ...
GROUP BY EmployeeID;
You can format it pretty on the front end. Or in T-SQL:
;WITH w(e, mw) AS
(
SELECT EmployeeID, SUM(DATEDIFF(MINUTE, '0:00:00', WrkHrs))
FROM dbo.table
-- WHERE ...
GROUP BY EmployeeID
)
SELECT EmployeeID = e,
WrkHrs = RTRIM(mw/60) + ':' + RIGHT('0' + RTRIM(mw%60),2)
FROM w;
However, you're using the wrong data type. TIME is used to indicate a point in time, not an interval or duration. Wouldn't it make sense to store their work hours in two distinct columns, StartTime and EndTime?
In order to sum up the working hours for an employee you can calculate the difference between the shift start time and end time in minutes and convert it to readable format as following:
DECLARE #StartTime datetime = '08:00'
DECLARE #EndTime datetime = '10:47'
DECLARE #durMinutes int
DECLARE #duration nvarchar(5)
SET #durMinutes = DATEDIFF(MINUTE, #StartTime, #EndTime)
SET #duration =
(SELECT RIGHT('00' + CAST((#durMinutes / 60) AS VARCHAR(2)),2) + ':' +
RIGHT('00' + CAST((#durMinutes % 60) AS VARCHAR(2)), 2))
SELECT #duration
The result : 02:47
two hours and 47 minutes
select DATEDIFF(MINUTE, '0:00:00', '00:02:08')
results in :- 2
select DATEDIFF(SECOND, '0:00:00', '00:02:08')
results in :- 128
Using seconds gives a better answer.
So I think the answer can be
SELECT
EmployeeId
, seconds_worked = SUM (DATEDIFF (SECOND, '0:00:00', WrkHrs))
FROM
tbl_employee
GROUP BY
EmployeeId;
DECLARE #Tab TABLE
(
data CHAR(5)
)
INSERT #Tab
SELECT '25:30' UNION ALL
SELECT '31:45' UNION ALL
SELECT '16:00'
SELECT STUFF(CONVERT(CHAR(8), DATEADD(SECOND, theHours + theMinutes,
'19000101'), 8), 1, 2, CAST((theHours + theMinutes) / 3600 AS VARCHAR(12)))
FROM (
SELECT ABS(SUM(CASE CHARINDEX(':', data) WHEN 0 THEN 0 ELSE 3600 *
LEFT(data, CHARINDEX(':', data) - 1) END)) AS theHours,
ABS(SUM(CASE CHARINDEX(':', data) WHEN 0 THEN 0 ELSE 60 *
SUBSTRING(data, CHARINDEX(':', data) + 1, 2) END)) AS theMinutes
FROM #Tab
) AS d
For MS SQL Server, when your WorkingTime is stored as a time, or a varchar in order to sum it up you should consider that:
1) Time format is not supporting sum, so you need to parse it
2) 23:59:59.9999999 is the maximum value for the time.
So, the code that will work to get you the total number of WorkingHours:WorkingMinutes:WorkingSeconds would be the following:
SELECT
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) / 3600),'00') as varchar(max)) + ':' +
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) % 3600 / 60),'00') as varchar(max)) + ':' +
CAST(FORMAT((SUM((DATEPART("ss",WorkingTime) + DATEPART("mi",WorkingTime) * 60 + DATEPART("hh",WorkingTime) * 3600)) % 3600 % 60),'00') as varchar(max)) as WorkingTimeSum
FROM TableName
It must be as simple as that.
Steps
convert time to seconds
sum the RESULT
convert the sum to time
Eg:
take a case you might want to sum the following time:
| present_hours |
|-----------------|
| 00:01:20.000000 |
|-----------------|
| 00:01:13.000000 |
|-----------------|
| 00:01:45.000000 |
|-----------------|
| 00:01:03.000000 |
|-----------------|
| 00:01:10.000000 |
|-----------------|
| 00:00:56.000000 |
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(present_hours))) as total_present_hours FROM time_booking;

How to convert hh:mm:ss to seconds in SQL Server with more than 24 hours

I have table name tblAttend in which one column named WorkHrs is of datatype varchar.
The result of simple select query is
I sum this column's value and get result in seconds my query is
select sum(DATEDIFF(SECOND, '0:00:00', WorkHrs ))
from tblAttend
and it shows this output:
Now the issue is, when sum of WorkHrs is greater than 24 hours it will throw an error:
What can you suggest to get around this problem? Thanks in advance
Try splitting each time into its component parts by converting the time to a string and then multiplying by the number of seconds relevant to each part.
Data conversion to integer is implicit
select Sum(Left(WorkHrs,2) * 3600 + substring(WorkHrs, 4,2) * 60 + substring(WorkHrs, 7,2))
from tblAttend
Try:
DECLARE #DURATION TIME = '01:43:24'
SELECT DATEDIFF(SECOND, '1/1/1900', CONVERT(DATETIME, #DURATION))
Try this:
SELECT DATEDIFF(SECOND, CONVERT(DATE,GETDATE()), GETDATE())
I have implemented the following function to use it in the management of my projects :
/****** Object: UserDefinedFunction [dbo].[Seconds] Script Date: 10/6/2017 12:00:22 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
select [dbo].[Seconds]('24:00:00'),(24*3600)
select [dbo].[Seconds]('102:56:08'),(102*3600+56*60+8)
*/
ALTER FUNCTION [dbo].[Seconds] (#Time as varchar(50))
RETURNS int
BEGIN
declare #S int, #H int
set #H=cast(SUBSTRING(#Time,1,CHARINDEX(':',#Time)-1) as int)
IF #H<24
set #S=DATEDIFF(SECOND, '0:00:00', #Time)
ELSE BEGIN
set #H=#H-23
set #Time = '23'+SUBSTRING(#Time,CHARINDEX(':',#Time),LEN(#Time)-2)
set #S = (#H*3600)+DATEDIFF(SECOND, '0:00:00', #Time)
END
RETURN #S
END
You may try like this:
SELECT Sec=SUM((DATEPART(HOUR,column name)*3600)+(DATEPART(MINUTE,column name)*60)+(DATEPART(Second,column name)))
FROM [TableName]
You need to convert your WorkHrs to DATETIME first, then perform the DATEDIFF:
WITH Cte(WorkHrs) AS(
SELECT CAST('02:29:11' AS VARCHAR(10)) UNION ALL
SELECT CAST('21:00:00' AS VARCHAR(10)) UNION ALL
SELECT CAST('25:20:02' AS VARCHAR(10))
),
CteConvert(dt) AS(
SELECT
DATEADD(
SECOND,
CAST(SUBSTRING(WorkHrs, 7, 2) AS INT),
DATEADD(
MINUTE,
CAST(SUBSTRING(WorkHrs, 4, 2) AS INT),
DATEADD(
HOUR,
CAST(SUBSTRING(WorkHrs,1, 2) AS INT),
0
)
)
)
FROM Cte
)
SELECT
SUM(DATEDIFF(SECOND, 0, dt)),
-- Formatted to hh:mm:sss
RIGHT('0' + RTRIM(CONVERT(CHAR(2), SUM(DATEDIFF(SECOND, 0, dt)) / (60 * 60))), 2) + ':' +
RIGHT('0' + RTRIM(CONVERT(CHAR(2), (SUM(DATEDIFF(SECOND, 0, dt)) / 60) % 60)), 2) + ':' +
RIGHT('0' + RTRIM(CONVERT(CHAR(2), SUM(DATEDIFF(SECOND, 0, dt)) % 60)),2)
FROM CteConvert
;with cte as (
select
total =Sum(Left(WorkHrs,2) * 3600 + substring(WorkHrs, 4,2) * 60 + substring(WorkHrs, 7,2))
from tblAttend
)
select
total [Total Time in Seconds],
(total / 3600) [Total Time Hour Part],
((total % 3600) / 60) [Total Time Minute Part],
(total % 60) [Total Time Second Part]
from cte
I think you can isolate each part of the time (hour, minute and second) and than sum what you need, please take a look:
declare #tbl table(WorkHrs VARCHAR(8))
insert into #tbl(WorkHrs) values ('02:29:11')
insert into #tbl(WorkHrs) values ('25:00:11')
-- Sum in minutes
SELECT TRY_CAST(([HOURS] * 60) + [MINUTES] + ([SECOND] / 60) AS INT) as TotalInMinutes
FROM (
SELECT
-- Use this aproach to get separated values
SUBSTRING(WorkHrs,1,CHARINDEX(':',WorkHrs)-1) AS [HOURS],
SUBSTRING(WorkHrs,4,CHARINDEX(':',WorkHrs)-1) AS [MINUTES],
SUBSTRING(WorkHrs,7,CHARINDEX(':',WorkHrs)-1) AS [SECOND] -- probably you can ignore this one
FROM #tbl
)
tbl
-- Or try to sum in seconds
SELECT TRY_CAST(([HOURS] * 3600) + ([MINUTES] * 60) + [SECOND] AS INT) as TotalInSeconds
FROM (
SELECT
-- Use this aproach to get separated values
SUBSTRING(WorkHrs,1,CHARINDEX(':',WorkHrs)-1) AS [HOURS],
SUBSTRING(WorkHrs,4,CHARINDEX(':',WorkHrs)-1) AS [MINUTES],
SUBSTRING(WorkHrs,7,CHARINDEX(':',WorkHrs)-1) AS [SECOND]
FROM #tbl
)
tbl
It will return like this to you:
I hope it can help
You can simply use the TIME_TO_SEC function:
SELECT TIME_TO_SEC(WorkHrs) FROM tblAttend;

How to get sum of time field in SQL server 2008

I am facing a problem in finding the sum of values stored in a column,
I have a table like this:
gs_cycle_no | from_time | to_time | total_hours(varchar) ...
GSC-334/2012 | 13:00 | 7:00 | 42:00
GSC-334/2012 | 8:30 | 3:45 | 6:00
.
.
.
What i need to find is the Sum(total_hours) group by gs_cycle_no.
But the Sum method will not work on the varchar column and also i cant convert it to decimal due to its format,
How can i find the sum of total_hours column, based on gs_cycle_no?
if you have no minutes and only hours, then you can do something like:
select
cast(sum(cast(replace(total_hours, ':', '') as int) / 100) as nvarchar(max)) + ':00'
from Table1
group by gs_cycle_no
if you don't, try this:
with cte as
(
select
gs_cycle_no,
sum(cast(left(total_hours, len(total_hours) - 3) as int)) as h,
sum(cast(right(total_hours, 2) as int)) as m
from Table1
group by gs_cycle_no
)
select
gs_cycle_no,
cast(h + m / 60 as nvarchar(max)) + ':' +
right('00' + cast(m % 60 as nvarchar(max)), 2)
from cte
sql fiddle demo
This will work:
;with times as (
select gs_cycle_no = 'GSC-334/2012', total_hours = '8:35'
union all SELECT gs_cycle_no = 'GSC-334/2012', '5:00'
union all SELECT gs_cycle_no = 'GSC-334/2012', '16:50'
union all SELECT gs_cycle_no = 'GSC-334/2012', '42:00'
union all SELECT gs_cycle_no = 'GSC-335/2012', '0:00'
union all SELECT gs_cycle_no = 'GSC-335/2012', '175:52'
union all SELECT gs_cycle_no = 'GSC-335/2012', '12:25')
SELECT
gs_cycle_no,
hrs = sum(mins) / 60 + sum(hrs),
mins = sum(mins) % 60
FROM
TIMES
cross apply(
select c = charindex(':', total_hours)
) idx
cross apply(
select
hrs = cast(substring(total_hours, 1, c - 1) as int),
mins = cast(substring(total_hours, c + 1, len(total_hours)) as int)
) ext
group by gs_cycle_no
order by gs_cycle_no
This query finds sum in minutes:
SQLFiddle demo
select gs_cycle_no,
SUM(
CAST(
ISNULL(
substring(total_hours,1,CHARINDEX(':',total_hours)-1)
,'0') as INT) * 60
+
CAST(
ISNULL(
substring(total_hours,CHARINDEX(':',total_hours)+1,100)
,'0') as INT)
)
from t
group by gs_cycle_no
Here is solution where I break varchar into two small pieces, hours and minutes, and then make minutes from them, and at last, SUM them:
SELECT
gs_cycle_no,
CAST(SUM(
SUBSTRING(total_hours,0 ,CHARINDEX(':', total_hours)) * 60 +
SUBSTRING(total_hours, CHARINDEX(':', total_hours) + 1, LEN(total_hours))) / 60 AS VARCHAR) + ':' +
CAST(SUM(
SUBSTRING(total_hours,0 ,CHARINDEX(':', total_hours)) * 60 +
SUBSTRING(total_hours, CHARINDEX(':', total_hours) + 1, LEN(total_hours))) % 60 AS VARCHAR)
FROM Table1
GROUP BY gs_cycle_no

Sum of time in sql

I have a table like this...
create table test
(
dt datetime
)
In that table the datetime are as follows,
2011/02/02 12:55:00
2011/03/05 00:40:00
2011/02/03 00:12:00
I want to calculate sum hours,mi,ss
In a single Select query not sp.
If any one know please tell me.
Thanks ...
You could sum the times as seconds, then convert to hours, minutes and seconds:
select TotalSeconds / 3600 as [Hours], (TotalSeconds % 3600) / 60 as [Minutes], (TotalSeconds % 3600) % 60 as [Seconds]
from
(
select sum(datepart(hour, dt) * 3600) + sum(datepart(minute, dt) * 60) + sum(datepart(second, dt)) as TotalSeconds
from test
) t
Assuming the sum won't be more than 999 hours:
DECLARE #t TABLE(dt DATETIME);
INSERT #t SELECT '20110202 12:55'
UNION SELECT '20110305 00:40'
UNION SELECT '20110203 00:12';
WITH s AS
(
SELECT s = SUM(DATEDIFF(SECOND,
DATEADD(DAY, 0, DATEDIFF(DAY, 0, dt)), dt))
FROM #t
)
SELECT
s,
hhmmss = RIGHT('000' + RTRIM(s/3600), 3)
+ ':' + RIGHT('00' + RTRIM((s % 3600) / 60), 2)
+ ':' + RIGHT('00' + RTRIM((s % 3600) % 60), 2)
FROM s;
However, if what you are really storing is duration, why not store the number of seconds instead of wedging your data into an inappropriate data type that requires all kinds of workarounds to process properly?
Declare #Table Table
(
DateTimeCol DateTime
)
insert into #Table values ( '2011/02/02 12:55:00')
insert into #Table values ('2011/03/05 00:40:00')
insert into #Table values ('2011/02/03 00:12:00')
;with CTE As
(
--first of all find total seconds of datecolumn
--sum all seconds
Select SUM(
(datepart(hour,DateTimeCol)*60*60)+(datepart(minute,DateTimeCol)*60)+(datepart(second,DateTimeCol))
) As TotalSecond
From #Table
)
--devides with 3600 to get the total hours and then to 60 to get total minutes
Select CONVERT(VARCHAR(10),TotalSecond/3600)+ '.' +
CONVERT(VARCHAR(20),TotalSecond%3600/60) + '.' +
CONVERT(VARCHAR(20),TotalSecond%3600%60) AS [Time] --Total of Time
From CTE

SQL: float number to hours format

Is there a easy way to format a float number in hours in Ms SQL server 2008?
Examples:
1.5 -> 01:30
9.8 -> 09:48
35.25 -> 35:15
Thanks a lot.
I like this question!
DECLARE #input float = 1.5;
DECLARE #hour int = FLOOR(#input);
DECLARE #minutes int = (SELECT (#input - FLOOR(#input)) * 60);
SELECT RIGHT('00' + CONVERT(varchar(2), #hour), 2) + ':' + RIGHT('00' + CONVERT(varchar(2), #minutes), 2);
SELECT SUBSTRING(CONVERT(NVARCHAR, DATEADD(MINUTE, 1.5*60, ''), 108), 1, 5)
This works by:
starting from the "zero" date
adding 1.5 x 60 minutes (i.e. 1.5 hours)
formatting the result as a time, hh:mm:ss (i.e. format "108")
trimming off the seconds part
It is necessary to use 1.5 x 60 minutes instead of 1.5 hours as the DATEADD function truncates the offset to the nearest integer. If you want high-resolution offsets, you can use SECOND instead, suitable scaled (e.g. hours * 60 * 60).
Sure. Easy, but not exactly...straightforward:
declare #hours float
set #hours = -9.8
select substring('- ',2+convert(int,sign(#hours)),1) -- sign
+ right('00' + convert(varchar, floor(abs(#hours))) , 2 ) -- hours component
+ ':' -- delimiter
+ right('00' + convert(varchar,round( 60*(abs(#hours)-floor(abs(#hours))) , 0 ) ) , 2 ) -- minutes
Another option that will give the correct result. You might need to tweak it to round minutes and to ensure that both fields are 2 digits wide.
declare #hours float
set #hours = -9.8
select convert(varchar, datediff(minute,dateadd(minute,#hours*60,convert(datetime,'')),'') / 60 )
+ ':' + convert(varchar, datediff(minute,dateadd(minute,#hours*60,convert(datetime,'')),'') % 60 )
WITH m AS
SELECT Minutes = CAST(#hours * 60 AS int)
)
SELECT CAST(Minutes / 60 AS varchar) + ':' + RIGHT(100 + Minutes % 60, 2)
FROM m
select dateadd(MINUTE, cast((8.18 % 1) * 60 as int), dateadd(hour, cast(8.18 as int), convert(varchar(10), getdate(), 10)))