Calculation more than 24 hours in SQL Server 2008 - sql

I have multiple records as workinghours of employee as
02:10:00
03:00:00
12:00:00
12:34:56
Now i need to add these record and want to display in
`hh:mm:ss`
Format. I used following query but it only works when sum of record less than 24 hours but record may be greater than 24 hours.
SELECT CAST(DATEADD(MILLISECOND,
SUM(DATEDIFF(MILLISECOND, '00:00:00.000'
, CAST(WorkHrs AS TIME))), '00:00:00.000') AS TIME) AS Total_Time
FROM tblAttend
I spend more than 4 hours on google to find solution but got no success anymore.
Datatype of workinghour column is varchar .

The time data type has an explicit range only up to 24 hours (see here).
So, I think you are basically stuck with doing the conversion yourself. It is ugly, but looks something like:
SELECT RIGHT('00' + CAST(SUM(DATEDIFF(MILLISECOND, '00:00:00.000', CAST(WorkHrs AS TIME))), '00:00:00.000')/(60*60) AS VARCHAR(255)), 2)
) +
RIGHT('00' + CAST((SUM(DATEDIFF(MILLISECOND, '00:00:00.000', CAST(WorkHrs AS TIME))), '00:00:00.000')/60 % 60) AS VARCHAR(255)), 2) +
RIGHT('00' + CAST(SUM(DATEDIFF(MILLISECOND, '00:00:00.000', CAST(WorkHrs AS TIME))), '00:00:00.000') % 60 AS VARCHAR(255)), 2)
)

Merhaba Waqas,
Could you please try following SQL CTE Select statement,
It returns hours value more than 24, for this case it was 29 I guess.
Please check time calculation on SQL Server, this select is adapted from there
;with cte as (
select
userid,
total = sum( DATEPART(ss,period) + 60 * DATEPART(mi,period) + 3600 * DATEPART(hh,period) )
from WorkingHours
group by userid
)
select
userid,
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 hope it helps you

Related

Extracting Day/Hour/Minute

I have the following code which is working, however how do I get the terminal minutes to show the output as Day, Hour, Minute? If this cannot be done, is it possible to add a +1 on the time which would indicate it's the following day?
The problem I am having is that when our orders run past 23.59 PM, the system is not displaying the correct format because of the 24 hour time period.
I am stumped and hope I am not confusing matters.
SELECT FOLIO_NUMBER, TERMINAL_NAME,
format((START_LOAD_TIME - ORDER_ENTRY_TIME), 'HH:mm') AS STAGING_MINUTES,
format((TERM_END_LOAD_TIME - START_LOAD_TIME), 'HH:mm') AS LOADING_MINUTES,
format((TERM_END_LOAD_TIME - ORDER_ENTRY_TIME), 'HH:mm') AS TERMINAL_MINUTES
FROM ORDERS
JOIN TERMINAL_OWNER ON ORDERS.LOADING_TERMINAL_ID = TERMINAL_OWNER.TERMINAL_ID
DECLARE #INT INT
SET #INT = DATEDIFF(SECOND,GETDATE(),GETDATE()+1)
select
convert(varchar(10), (#INT/86400)) + ':' +
convert(varchar(10), ((#INT%86400)/3600)) + ':'+
convert(varchar(10), (((#INT%86400)%3600)/60)) + ':'+
convert(varchar(10), (((#INT%86400)%3600)%60)) as 'DD:HH:MM:SS'
Courtesy of Nat-MS. See here
I think you are looking for something like this
Declare #theMinutes Varchar(10)
Set #theMinutes = '19:25'
declare #totMintute int
Select
#totMintute = (Cast(
Cast(left(#theMinutes,charindex(':',#theMinutes)-1) as Int) * 60
+ Cast(substring(#theMinutes,charindex(',',#theMinutes)+4,len(#theMinutes)) as Int)
as Int ) * 60) / 60
--For 12 hour 1 days
Select #totMintute / 720 as NoDays -- 720 minutes per day
, (#totMintute % 720) / 60 as NoHours -- modulo 720
, (#totMintute % 60) as NoMinutes -- modulo 60
--For 24 hour 1 days
Select #totMintute / 1440 as NoDays -- 1440 minutes per day
, (#totMintute % 1440) / 60 as NoHours -- modulo 1440
, (#totMintute % 60) as NoMinutes -- modulo 60
The output will look like as shown below.
You can convert this query data source table as shown below.
Create table #Temp (MinValue Varchar(8))
insert into #Temp Values ('19:25')
Select TotMinute / 720 as NoDays -- 1440 minutes per day
, (TotMinute % 720) / 60 as NoHours -- modulo 1440
, (TotMinute % 60) as NoMinutes -- modulo 60
from(
select
(Cast(
Cast(left(MinValue,charindex(':',MinValue)-1) as Int) * 60
+ Cast(substring(MinValue,charindex(',',MinValue)+4,len(MinValue)) as Int)
as Int ) * 60) / 60 as TotMinute
from #Temp
)a
You can find the live demo here.
I would say that you should remove the need to identify days/hours in the SQL Output and just get the difference in minutes, which you can then work with in your application layer.
Take this sample code:
create table #orders (
FOLIO_NUMBER int,
START_LOAD_TIME datetime,
ORDER_ENTRY_TIME datetime,
TERM_END_LOAD_TIME datetime
)
insert into #orders (FOLIO_NUMBER,START_LOAD_TIME,ORDER_ENTRY_TIME,TERM_END_LOAD_TIME)
values (1, getdate(),getdate() - 1,getdate() + 1)
select *,
datediff(mi, ORDER_ENTRY_TIME, START_LOAD_TIME) AS STAGING_MINUTES,
datediff(mi, START_LOAD_TIME, TERM_END_LOAD_TIME) AS LOADING_MINUTES,
datediff(mi, ORDER_ENTRY_TIME, TERM_END_LOAD_TIME) AS TERMINAL_MINUTES
from #orders
drop table #orders
This will output the minutes difference between the events:
FOLIO_NUMBER STAGING_MINUTES LOADING_MINUTES TERMINAL_MINUTES
1 1440 1440 2880
You can then perform some simple maths with these values to extract, days, hours and minutes.

SUM of a group of time differences in T-SQL?

I want to sum all the time differences to show the total hours worked.
select
aaaa
from
employee B
inner join
(select
s.emp_reader_id,
Sum(case when s.in_time is not null and s.out_time is not null and s.shift_type_id=5 and LOWER(DATENAME(dw, [att_date]))='friday'then
cast(datediff(minute,'00:00:00', '23:59:59') / 60 +
(datediff(minute,'00:00:00', '23:59:59') % 60 / 100.0) as decimal(7, 4)
) end) as aaaa
from
Daily_attendance_data s
left outer join
employee bb on s.emp_reader_id = bb.emp_reader_id
where
att_date between '2018-10-01' and '2018-10-31'
and s.emp_reader_id = 1039
group by
s.emp_reader_id) A on B.emp_reader_id = A.emp_reader_id
Current output:
aaaa
47.1800
which gives the list of times by hours but then I want to sum it up to a grand total.
It would just total
Sample data :
23:59
23:59
Expected output:
47.58
I think you should convert all times to seconds, calculate the SUM then convert the total to HH:mm:ss.
Calculate The SUM of seconds
DECLARE #TimeinSecond as integer = 0
select #TimeinSecond = Sum(DATEDIFF(SECOND, '0:00:00', [WorkHrs]))
from Daily_attendance_data
Convert the HH:mm:ss Format
SELECT RIGHT('0' + CAST(#TimeinSecond / 3600 AS VARCHAR),2) + ':' +
RIGHT('0' + CAST((#TimeinSecond / 60) % 60 AS VARCHAR),2) + ':' +
RIGHT('0' + CAST(#TimeinSecond % 60 AS VARCHAR),2)
References
How to convert hh:mm:ss to seconds in SQL Server with more than 24 hours
SQL SERVER – Convert Seconds to Hour : Minute : Seconds Format
If your date type is DateTime.
you can try to let your value split two part.
hours get value need to condider carry from minutes so do SUM(intpart) + SUM(floatpart) / 60
minutes get value from SUM(floatpart) % 60
look like this.
SELECT concat(SUM(intpart) + SUM(floatpart) / 60,':', SUM(floatpart) % 60)
FROM (
SELECT cast(SUBSTRING (cast(col as varchar),0,3) as int) intpart,
cast(SUBSTRING (cast(col as varchar),CHARINDEX(':',col) +1,2)as int) floatpart
FROM T
) t1
sqlfiddle

SQL total hours from varchar column

I can't seem to find out how to get the total number of hours from varchar column from SQL Server 2016.
Query:
SELECT taakuren
FROM taken
Returns
10:00
12:15
26:00
40:00
I would like it to return
88:15
I've tried things like below query but a always end up with issue when it gets past 24 hours
select Convert(Varchar, (Convert(DateTime, taakuren)), 114) as TotalTime
from taken
Basically, the time data type peters out at 24 hours. If you want more hours, then you may have to resort to your own arithmetic:
select cast(sum(hours * 60 + minutes) / 60 as varchar(10)) + ':' +
right('00' + cast(sum(hours * 60 + minutes) % 60 as varchar(10)))
from taken t outer apply
(values (left(t.taakuren, 2) + 0, right(t.taakuren, 2) + 0)
) v(hours, minutes);
update my code is:
select cast(sum(hours * 60 + minutes) / 60 as varchar(10)) + ':' +
cast(sum(hours * 60 + minutes) % 60 as varchar(10))
from taken t outer apply
(values (left(t.taakuren, 2) + 0, SUBSTRING(t.taakuren, 4,6) + 0)
) v(hours, minutes)

Query to group data by 5 second time intervals

I have a table that has events that occur over a period of 1 hour.
2014-04-16 13:56:06.971 , 3474
2014-04-16 13:56:07.061 , 3609
2014-04-16 13:56:07.067 , 3617
The Table has the Time stamp and event ID
I am trying to group the data to have a count of the number of events that occurred with 5 second intervals, so it looks like this:
0-5 sec., 3
5-10 sec. , 6
10-15 sec. , 4
Thanks in Advance!
I am using SQL Server 2008
You can use a query like that:
declare #Hour datetime = '2014-04-16 13:00:00' -- starting time
select
CONVERT(VARCHAR(10), (DATEDIFF(second, #Hour, EventDateTime) / 5) * 5)
+ '-' + CONVERT(VARCHAR(10), (DATEDIFF(second, #Hour, EventDateTime) / 5 + 1) * 5) + ' sec',
COUNT(EventId)
from intervals
group by DATEDIFF(second, #Hour, EventDateTime) / 5
How about something like this, where you group by the seconds / 12
select
convert(varchar(5),[time stamp],108) as [hh:mm],
cast(min(datepart(s, [time stamp])) as varchar(10)) + ' - ' + cast(max(datepart(s, [time stamp])) as varchar(10)) as [second interval],
count(*) as total
from yourtable
group by convert(varchar(5),[time stamp],108), (datepart(s, [time stamp]) / 12)
or you could create a tally table with the start/end seconds and then join to it.

DATEDIFF in HH:MM:SS format

I need to calculate the total length in terms of Hours, Minutes, Seconds, and the average length, given some data with start time and end time.
For example the result must be something like 45:15:10 which means 45 hours 15 min 10 sec, or 30:07 for 30 min 07 sec.
We're using SQL Server 2008 R2 and the conversion failed when time is more than 24:59:59. Any idea of how I could do this?
For information, the columns in the table are Id, StartDateTime, EndDateTime, etc. I need to make a monthly report which contains the recordings count of the month, the total length of these records, and the average length. I'd like to know if there is an easy way to perform all of this.
You shouldn't be converting to time - it is meant to store a point in time on a single 24h clock, not a duration or interval (even one that is constrained on its own to < 24 hours, which clearly your data is not). Instead you can take the datediff in the smallest interval required (in your case, seconds), and then perform some math and string manipulation to present it in the output format you need (it might also be preferable to return the seconds to the application or report tool and have it do this work).
DECLARE #d TABLE
(
id INT IDENTITY(1,1),
StartDateTime DATETIME,
EndDateTime DATETIME
);
INSERT #d(StartDateTime, EndDateTime) VALUES
(DATEADD(DAY, -2, GETDATE()), DATEADD(MINUTE, 15, GETDATE())),
(GETDATE() , DATEADD(MINUTE, 22, GETDATE())),
(DATEADD(DAY, -1, GETDATE()), DATEADD(MINUTE, 5, GETDATE())),
(DATEADD(DAY, -4, GETDATE()), DATEADD(SECOND, 14, GETDATE()));
;WITH x AS (SELECT id, StartDateTime, EndDateTime,
d = DATEDIFF(SECOND, StartDateTime, EndDateTime),
a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER()
FROM #d
)
SELECT id, StartDateTime, EndDateTime,
[delta_HH:MM:SS] = CONVERT(VARCHAR(5), d/60/60)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2),
[avg_HH:MM:SS] = CONVERT(VARCHAR(5), a/60/60)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2)
FROM x;
Results:
id StartDateTime EndDateTime delta_HH:MM:SS avg_HH:MM:SS
-- ------------------- ------------------- -------------- ------------
1 2013-01-19 14:24:46 2013-01-21 14:39:46 48:15:00 42:10:33
2 2013-01-21 14:24:46 2013-01-21 14:46:46 0:22:00 42:10:33
3 2013-01-20 14:24:46 2013-01-21 14:29:46 24:05:00 42:10:33
4 2013-01-17 14:24:46 2013-01-21 14:25:00 96:00:14 42:10:33
This isn't precisely what you asked for, as it won't show just MM:SS for deltas < 1 hour. You can adjust that with a simple CASE expression:
;WITH x AS (SELECT id, StartDateTime, EndDateTime,
d = DATEDIFF(SECOND, StartDateTime, EndDateTime),
a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER()
FROM #d
)
SELECT id, StartDateTime, EndDateTime,
[delta_HH:MM:SS] = CASE WHEN d >= 3600 THEN
CONVERT(VARCHAR(5), d/60/60) + ':' ELSE '' END
+ RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2),
[avg_HH:MM:SS] = CASE WHEN a >= 3600 THEN
CONVERT(VARCHAR(5), a/60/60) + ':' ELSE '' END
+ RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2)
FROM x;
This query changes the delta column in the 2nd row in the above result from 0:22:00 to 22:00.
I slightly modified Avinash's answer as it may end with error if difference is too big. If you need only HH:mm:ss it is sufficient to distinguish at seconds level ony like this:
SELECT CONVERT(time,
DATEADD(s,
DATEDIFF(s,
'2018-01-07 09:53:00',
'2018-01-07 11:53:01'),
CAST('1900-01-01 00:00:00.0000000' as datetime2)
)
)
SELECT CONVERT(time,
DATEADD(mcs,
DATEDIFF(mcs,
'2007-05-07 09:53:00.0273335',
'2007-05-07 09:53:01.0376635'),
CAST('1900-01-01 00:00:00.0000000' as datetime2)
)
)
If you want to do averages, then the best approach is to convert to seconds or fractions of a day. Day fractions are convenient in SQL Server, because you can do things like:
select avg(cast(endtime - starttime) as float)
from t
You can convert it back to a datetime using the reverse cast:
select cast(avg(cast(endtime - starttime as float) as datetime)
from t
The arithmetic to get the times in the format you want . . . that is a pain. You might consider including days in the final format, and using:
select right(convert(varchar(255), <val>, 120), 10)
To get the hours exceeding 24, here is another approach:
select cast(floor(cast(<val> as float)*24) as varchar(255))+right(convert(varchar(255), <val>, 120), 6)
It uses convert for minutes and seconds, which should be padded with 0s on the left. It then appends the hours as a separate value.
Starting in SQL SERVER 2012, you don't need to use DATEDIFF function. You can use FORMAT function to achieve what you want:
SELECT
FORMAT(CONVERT(TIME, [appoitment].[Start] - [appointment].[End]), N'hh\:mm') AS 'Duration'
FROM
[tblAppointment] (NOLOCK)
A way that avoids overflows and can include days and go all the way to milliseconds in the output:
DECLARE #startDate AS DATETIME = '2018-06-01 14:20:02.100'
DECLARE #endDate AS DATETIME = '2018-06-02 15:23:09.000'
SELECT CAST(DATEDIFF(day,'1900-01-01', #endDate - #startDate) AS VARCHAR) + 'd ' + CONVERT(varchar(22), #endDate - #startDate, 114)
The above will return
1d 01:03:06:900
And, off course, you can use the formatting of your choice
SQL Supports datetime substraction which outputs a new datetime relative to the MIN date (for instance 1900-01-01, you can probably get this value from some system variable) This works better than DATEDIFF, because DATEDIFF will count ONE for each "datepart boundaries crossed", even if the elapsed time is less than a whole datapart. Another nice thing about this method is that it allows you to use the date formatting conversions.
If days is the (positive) number of days, like 0.5 for 12 hours, use this expression to format it as a proper duration:
CONVERT(varchar(9), FLOOR(days * 24)) + RIGHT(CONVERT(char(19), CAST(days AS datetime), 120), 6)
Excel will understands values up to 9999:59:59 when pasted. There apply a custom format: [h]:mm:ss in the English version ([u]:mm:ss for Dutch).