converting int to hh:mm format - sql-server

I have separate integers for hours and minutes and i need to find a way to get the total number of hours followed by minutes preferably in a HH:MM format. The issue that i'm facing is when the minutes are less than ten there is no leading zero and i am doing this for reporting reasons and so would love to be able to do something like
Total Hours worked
102:06 to represent 102 hours and 6 minutes
DECLARE #hours INT = 102
declare #minutes int = 6
SELECT
CONCAT(CAST (SUM((#hours*60)+#minutes)/60 AS VARCHAR(5)) , ':' , CAST (SUM((#hours*60)+#minutes)%60 AS VARCHAR(2)))

In SQL Server, you can do:
select concat(hours, ':',
right('00' + minutes, 2)
)
Another method would be:
select concat(hours, ':',
right(convert(varchar(255), 100 + minutes), 2)
)

Just another similar option using format()
Example
DECLARE #hours INT = 102
declare #minutes int = 6
Select concat(#hours,format(#minutes,':00'))
Returns
102:06

Related

How to add two time values stored as decimal in SQL Server

I need to add two columns which stores time values as decimals
example:
1.) 8.30+0.32 = 9.02 (output should be 9.03 not 8.62)
The above mentioned example is working fine and is an actual output of the below SQL.
I wrote the below SQL which works fine predominantly, but I find few cases where the addition is not proper
Example: 3.57+5.25=18.44
SELECT
case when B.Column_B is null then A.Column_A
when B.Column_B is not null then
replace(CONVERT(varchar(5),
DATEADD(ss,(SUM((DATEPART(hh, replace(isnull(a.Column_A,0.00),'.',':'))*3600) + (DATEPART(mi,replace(isnull(a.Column_A,0.00),'.',':'))*60)) +
SUM((DATEPART(hh, replace(isnull(b.Column_B,0.00),'.',':'))*3600) + (DATEPART(mi,replace(isnull(b.Column_B,0.00),'.',':'))*60))),0),108) ,':','.')
End as "Total_Hours"
I am not able to find where this is going wrong in the above mentioned case. Is there anything wrong here or is there any better way of handling this addition
Try this:
DECLARE #Value01 DECIMAL(9,2) = 8.30
,#value02 DECIMAL(9,2) = 0.32;
SELECT CONCAT
(
(DATEDIFF(MINUTE, '0:00:00', CAST(REPLACE(#Value01, '.', ':') AS TIME)) + DATEDIFF(MINUTE, '0:00:00', CAST(REPLACE(#value02, '.', ':') AS TIME))) / 60
,'.'
,RIGHT((DATEDIFF(MINUTE, '0:00:00', CAST(REPLACE(#Value01, '.', ':') AS TIME)) + DATEDIFF(MINUTE, '0:00:00', CAST(REPLACE(#value02, '.', ':') AS TIME))) % 60 + 100, 2)
);
First, convert to TIME and get the total number of minutes. Then, format the minutes to Time but using . instead :.
Code
declare #v1 DECIMAL(9,3) = 4.369, -- 9 characters with 3 decimal places.
#v2 DECIMAL(9,3) = 3.368 -- 9 characters with 3 decimal places.
print #v1 + #v2
Output
7.737

convert decimal to time 6.80 =7.20 hrs in SQL [duplicate]

This question already has answers here:
Convert decimal time to hours and minutes
(4 answers)
Closed 9 years ago.
Please help me to do this
decimal 6.80 should equal to 7.20 hours
DECLARE #R1 decimal(4,2);
DECLARE #R2 decimal(4,2);
declare #Type1 decimal(4,2);
declare #Type2 decimal(4,2);
DECLARE #R1Time decimal(4,2);
DECLARE #R2Time decimal(4,2);
SET #R1=2.5
SET #R2=3.5
SET #Type1=17;
SET #Type2=7;
SET #R1Time=(FORMAT((ISNULL(60.0/NULLIF(#R1,0),0)),'N2'))
SET #R2Time=(FORMAT((ISNULL(60.0/NULLIF(#R2,0),0)),'N2'))
SELECT #R1Time as R1Min
SELECT #R2Time as R2Min
SELECT FORMAT(((#Type1*#R1Time)/60.0),'N2') R1Hrs -- 6.80 hours this = 24*17=408/60
SELECT FORMAT(((#Type2*#R2Time)/60.0),'N2') R2Hrs
SELECT CONVERT(CHAR(5), DATEADD(MINUTE, 60*(convert(decimal(4,2),FORMAT(((#Type1*#R1Time)/60.0),'N2'))), 0), 108);--6.48 hours
6.80 hours this = 24*17=408/60 this should be 7.20 hours not 6.48 is it?. Did I am wrong please help me thanks
#R1 is how many in an hour 60/2.5 =24min per Type1 and 17 Type1 is 17*24 =408 min then convert to time –
So what you are saying is that the number before the decimal seperator is correct (in hours) and the number after the decimal seperator is in the absolute amount of minutes?
Then in pseudocode you can do something like this:
INPUT = 6.80
HOURS = FLOOR(INPUT)
DECIMALS = (INPUT - HOURS) * 100
if ( DECIMALS > 60 )
{
HOURS = HOURS + 1
MINUTES = DECIMALS - 60
}
// Now hours and minutes are in the way you intended
Now all you have to do is convert this pseudocode into SQL code.
In function form, this would look something like this (I wrote this by heart so beware for typo's/ errors):
CREATE FUNCTION ChangeTime
-- Input current time decimal
(#CurrentTime decimal(2,1) )
RETURNS decimal(2,1) -- New time
AS
BEGIN
DECLARE #Hours int, #Minutes int;
SET #Hours = FLOOR(#CurrentTime);
SET #Minutes = (#CurrentTime - #Hours)*100;
IF #Minutes >= 60
BEGIN
SET #Hours = #Hours + 1; -- New hours
SET #Minutes = #Minutes - 60; -- New minutes
END
RETURN ( #Hours + (#Minutes/100) ) -- New (corrected) time
END
On the other hand, if you mean: I need to convert the decimals such that 6.50 becomes 6 hours and 30 minutes and 6.80 becomes 6 hours and 48 minutes, then we can change the function to the following:
CREATE FUNCTION ChangeTime
-- Input current time decimal
(#CurrentTime decimal(2,1) )
RETURNS decimal(2,1) -- New time
AS
BEGIN
DECLARE #Hours int, #Minutes int;
SET #Hours = FLOOR(#CurrentTime);
SET #Minutes = (#CurrentTime - #Hours)*100;
SET #Minutes = (#Minutes / 100) * 60; -- New minutes
RETURN ( #Hours + (#Minutes/100) ) -- New (corrected) time
END
If both of these functions do not get the desired result, then please update your question with an explanation of what you exactly want to achieve.
Good luck!
declare #hour decimal(6,2) = 6.8
select floor(#hour) + floor(#hour%1/.6) + #hour%1%.6
Result:
7.20
If you want it as a function:
CREATE FUNCTION f_convert(#hour decimal(6,2))
RETURNS decimal(6,2)
AS
BEGIN
RETURN floor(#hour) + floor(#hour%1/.6) + #hour%1%.6
END
Test(sqlserver 2008+):
SELECT dbo.f_convert(hour)
FROM (values (6.8),(3.9),(.59)) x(hour)
Result:
7.20
4.30
0.59

How to split minutes into days, hours and minutes in tsql

I have a column which consist of minutes. Is there any simple way to split minutes column into one column which shows days, hours, minutes only?
DURATION
-----------
67 ==> 1 hour, 7 minutes
1507 ==> 1 day, 1 hour, 7 minutes
23 ==> 23 minutes
I googled for solution but I didn't find any solution similar for me. I want to show this in a report but trying to find how can I solve this column looks meaningfully. Duration column's calculation like this.
avg(datediff(MINUTE, ei.SentDate, eo.SentDate)) over(partition by ei.mailbox) as DURATION
A google search landed me here http://www.sqlservercentral.com/Forums/Topic490411-8-1.aspx
and It says... which I just tested working ...
Declare #theMinutes int
Set #theMinutes = 67
Select #theMinutes / 1440 as NoDays -- 1440 minutes per day
, (#theMinutes % 1440) / 60 as NoHours -- modulo 1440
, (#theMinutes % 60) as NoMinutes -- modulo 60
create FUNCTION fun_Date_Friendly (#minutes int)
RETURNS nvarchar(100)
AS
BEGIN
return CASE
when #minutes < 60 then cast( #minutes as varchar(10)) + ' Min'
when #minutes < 1440 then cast(#minutes/60 as varchar(10)) + ' Hr, ' + cast(#minutes%60 as varchar(10)) + ' Min'
else cast(#minutes/(1440 ) as varchar(10)) + ' Days, ' + cast((#minutes%1440 )/60 as varchar(10)) + ' Hr, ' + cast(((#minutes%1440 )%60) as varchar(10)) + ' Min'
end
end
go
then just pass minutes to function
select dbo.fun_Date_Friendly(20) val

T-SQL formatting calculated column as time

Could use guru help on this one. Trying to calculate the time between two datetime values and show as time in a T-SQL query...
SELECT arrivalDate - departDate AS timeToComplete
This should always be less than 24 hours. But who knows what the user may actually input?
I have been trying something like this with no resutls.
SELECT
CAST(time(7),
CONVERT(datetime, arrivalDate - departDate) AS timeToComplete) AS newTime,
Instead of showing results as 1:23:41 as an example, is there a way to show results like:
0D, 1H, 23M, 33S.
Thanks for any guidance on this.
You could get the total difference in seconds and then keep taking the largest part out of that. I.e., start with Days, then hours, minutes and seconds.
DECLARE #arrivalDate DATETIME = '2013-01-19 23:59:59'
DECLARE #departDate DATETIME = '2013-01-25 11:52:30'
DECLARE #SecondsDifference INT = DATEDIFF(SECOND, #arrivalDate, #departDate)
DECLARE #DayDifference INT = #SecondsDifference / 86400
DECLARE #HourDifference INT = (#SecondsDifference - (#DayDifference * 86400)) / 3600
DECLARE #MinDifference INT = (#SecondsDifference - (#DayDifference * 86400) - (#HourDifference * 3600)) / 60
DECLARE #SecDifference INT = (#SecondsDifference - (#DayDifference * 86400) - (#HourDifference * 3600) - (#MinDifference * 60))
I've done it here using variables for clarity, but you could work this into a single query. DATEDIFF wont work for the smaller chunks of the difference until you remove the larger ones because you'd get the totals. For example:
DATEDIFF(HOUR, #arrivalDate, #departDate)
would return the total number of hours, not the hours less the whole days.
Just to be different :)
Try to use this approach:
declare #date1 datetime;
declare #date2 datetime;
set #date1 = '2012-05-01 12:00:000'
set #date2 = '2012-05-01 18:00:000'
SELECT
STUFF(
STUFF(
STUFF(
RIGHT(CONVERT(NVARCHAR(19), CONVERT(DATETIME, DATEADD(second, DATEDIFF(S, #date1, #date2), '20000101')), 120), 11),
3, 1, 'D, '),
8, 1, 'H, '),
13, 1, 'M, ') + ' S';
Finally found a great solution at this link,
SQL - Seconds to Day, Hour, Minute, Second
thanks for the help though folks, it got me further into this issue and searching for the right info.

what is the best way to store time interval in a SQL server database

i have a table where i want to track time so a valid entry might be:
1 hour 3 mins
47 mins
10 hours
3 mins 14 seconds
what field type is best used for this. i obviously could use varchar . .but i thought there might be something better as i would like to run queries to total the amount of time over a number of records.
Do not use character types to store date/time information.
In SQL Server 2008, you have the time type for this, which is what you should use if your time intervals are less than 1 day. In previous versions, or if you need to store larger intervals, you will have to use datetime or smalldatetime (depending on the precision you need).
Another option would be to choose a time unit - say, minutes - and just use an int value to represent the number of units. Just make sure that (a) the unit you choose is actually precise enough to record the smallest intervals you need to track, and (b) the actual numeric type is large enough to hold the largest intervals you need to track. A smallint might be sufficient for tracking the number of minutes within a day; on the other hand, tracking the number of milliseconds within a 10-year timeframe would have to be stored as a bigint.
Just use integer to store interval in seconds. DATEDIFF returns integer. Write a function that turns it into text. This one needs some adjustmens (so it shows "1 min", not "1 mins"), but should work ok:
CREATE FUNCTION dbo.SecondsToText(#seconds int)
RETURNS VARCHAR(100)
AS
BEGIN
declare #days int;
set #days = #seconds/(3600 * 24);
declare #hours int;
set #hours = (#seconds - #days * 3600 * 24) / 3600;
declare #minutes int;
set #minutes = (#seconds - #days * 3600 * 24 - #hours * 3600) / 60;
set #seconds = (#seconds - #days * 3600 * 24 - #hours * 3600 - #minutes * 60);
RETURN
RTRIM(CASE WHEN #days > 0 THEN CAST(#days as varchar) + ' days ' ELSE '' END +
CASE WHEN #hours > 0 THEN CAST(#hours as varchar) + ' hours ' ELSE '' END +
CASE WHEN #minutes > 0 THEN CAST(#minutes as varchar) + ' minutes ' ELSE '' END +
CASE WHEN #seconds > 0 THEN CAST(#seconds as varchar) + ' seconds ' ELSE '' END)
END
GO
As #Aaronaught said use a date/time or datetime (as necessary) data type to store your values; but these types only store an instance in time and not a time span or duration. You will need to use two fields to store an interval e.g. [time_span_start] and [time_span_end]. The difference between the two will give you the interval.
The longer answer to your question can be answered by downloading a copy of "Developing Time-Oriented Database Applications in SQL" by Richard T. Snodgrass. It's freely available as a PDF, have a look here:
http://www.cs.arizona.edu/~rts/publications.html
Depends on your range of time - either convert everything to seconds and just store that value as an INT, or if your span of times is larger, you might want to use fields for hours, minutes, seconds separately.
Also, SQL Server 2008 introduces a new TIME data type which allows you to store time-only values.
Related to Tony's answer, you can also use a single datetime column relative to a standard start time which is implicit for all intervals - for instance: 1/1/1900 12:00 AM.
In this case it is easy enough for storage:
INSERT INTO tbl (interval) VALUES (DATEADD(s, '1/1/1900', DATEDIFF(s, #starttime, #endtime))
Now this is not obviously easy for doing SUMs of rows, so you could think about adding persisted computed column(s) of DATEDIFF(s, '1/1/1900', interval) to provide seconds to perform SUMs.
Now, here's where it gets interesting for SQL Server:
Because of SQL Server's implementation for converting numbers to and from dates, 0 -> 1/1/1900 12:00 AM, 0.5 -> 1/1/1900 12:00 PM, 1 -> 1/2/1900 12:00 AM etc. i.e. the whole number is treated as the number of days since 1/1/1900 and the fractional part is the fraction within the day. So you CAN actually naively add these to get an interval.
And in fact:
SELECT CONVERT(DATETIME, 1) + CONVERT(DATETIME, 0) + CONVERT(DATETIME, 2) + CONVERT(DATETIME, 0.5)
gives '1900-01-04 12:00:00.000' as expected
So you can do this (going around SUM by converting):
DECLARE #datetest TABLE ( dt DATETIME NOT NULL )
INSERT INTO #datetest ( dt )
VALUES ( 0 )
INSERT INTO #datetest ( dt )
VALUES ( 1 )
INSERT INTO #datetest ( dt )
VALUES ( 2 )
INSERT INTO #datetest ( dt )
VALUES ( 0.5 )
SELECT *
FROM #datetest
SELECT CONVERT(DATETIME, SUM(CONVERT(FLOAT, dt)))
FROM #datetest
I'm not advocating doing this in general, YMMV, and any design solution you choose should be verified against all your requirements.

Resources