Convert number of minutes to hh:mm - sql-server

I have a column in a table that stores the number of minutes as a numeric(18,4) field named [course_access_minutes].
The stored values come from a blackboard database and look like this:
0.0500
0.0667
0.3667
up to
314.0833
625.8167
How do I convert these to time hh:mm, I've had a good look at the database documentation and all I can find is
course_access_minutes numeric(18,4) This is the number of minutes that the user accesses this course in total during this login session.
Can I assume that I can make a direct conversion from minutes into hours? I think I will take any values below 1 as 0 minutes. What is the best way to do this in SQL? Thanks in advance for your help.

Try this
SELECT CONVERT(varchar, DATEADD(s, 625.8167 * 60, 0), 108)
If the duration is longer than 24 hours you can use this
SELECT CONVERT(varchar, CAST(1877.4501 * 60 AS int) / 3600)
+ RIGHT(CONVERT(varchar, DATEADD(s, 1877.4501 * 60, 0), 108), 6)

You could use FLOOR like this
DECLARE #SampleData AS TABLE
(
Minutes numeric(18,4)
)
INSERT INTO #SampleData
VALUES
( 0.0500),
( 1.0500),
( 30.0500),
( 80.0500),
( 314.0833),
( 625.8167)
SELECT CONCAT(floor(sd.Minutes/60),':', CASE WHEN sd.Minutes - floor(sd.Minutes/60)*60 < 1 THEN '0'
ELSE FLOOR(sd.Minutes - floor(sd.Minutes/60)*60 )
END) AS hours
FROM #SampleData sd
Returns
hours
0:0
0:1
0:30
1:20
5:14
10:25

WITH _Samples AS (
SELECT CONVERT(numeric(18, 4), 0.0500) [course_access_minutes]
UNION ALL SELECT 0.0667
UNION ALL SELECT 0.3667
UNION ALL SELECT 314.0833
UNION ALL SELECT 625.8167
)
SELECT
S.course_access_minutes,
-- split out the number
FLOOR(S.course_access_minutes / 60) [hours],
FLOOR(S.course_access_minutes % 60) [minutes],
FLOOR((S.course_access_minutes - FLOOR(S.course_access_minutes)) * 60) [seconds],
-- to a string
CONVERT(varchar(10), FLOOR(S.course_access_minutes / 60))
+ ':' + RIGHT('00' + CONVERT(varchar(10), FLOOR(S.course_access_minutes % 60)), 2)
+ ':' + RIGHT('00' + CONVERT(varchar(10), FLOOR((S.course_access_minutes - FLOOR(S.course_access_minutes)) * 60)), 2) [time_string],
-- You could consider converting to the time data type if the values will never exceed the limit
-- time supports 00:00:00.0000000 through 23:59:59.9999999
-- 0 through 1439.9833333 ... 23 * 60 = 1380 + 59 = 1439 + (59 / 60) = 1439.9833333
-- (see: https://learn.microsoft.com/en-us/sql/t-sql/data-types/time-transact-sql)
CONVERT(time,
CONVERT(varchar(10), FLOOR(S.course_access_minutes / 60))
+ ':' + RIGHT('00' + CONVERT(varchar(10), FLOOR(S.course_access_minutes % 60)), 2)
+ ':' + RIGHT('00' + CONVERT(varchar(10), FLOOR((S.course_access_minutes - FLOOR(S.course_access_minutes)) * 60)), 2)
) [time]
FROM
_Samples S
(It wouldn't be difficult to further this idea and split out the fractional seconds as well.)
Which yields:
course_access_minutes hours minutes seconds time_string time
---------------------- ------ -------- -------- ------------ ----------------
0.0500 0 0 3 0:00:03 00:00:03.0000000
0.0667 0 0 4 0:00:04 00:00:04.0000000
0.3667 0 0 22 0:00:22 00:00:22.0000000
314.0833 5 14 4 5:14:04 05:14:04.0000000
625.8167 10 25 49 10:25:49 10:25:49.0000000

Note that this is going to be like Greg's answer, but I wanted to explain and simplify it.
You have minutes, so dividing them by 60 and flooring it (removing the decimal) gives the hours (without the minutes).
If you take the total minutes again, and remove (mod it by) the floored hours - which requires conversion to minutes by multiplying by 60 - you are left with the remaining minutes by essentially just finding out what is left after taking away that many groups of sixties:
SELECT FLOOR(course_access_minutes / 60) as Hours,
(FLOOR(course_access_minutes) % 60) as Minutes
FROM MyTable
If you want the decimal to appear for the amount of minute fractions (you want the seconds to appear, in decimal form), remove FLOOR.
If you want seconds in real numbers, keep FLOOR and use what Greg had: FLOOR((S.course_access_minutes - FLOOR(S.course_access_minutes)) * 60) for seconds. Be careful with the parenthesis, though, because you can end up accidentally flooring your decimaled minutes and get 0, and then 0*60 is zero:
FLOOR(
(
course_access_minutes -
FLOOR(course_access_minutes)
) * 60
) as Seconds

Related

How to convert HHMMSS to seconds using T-SQL

SQL server table msdb.dbo.sysjobhistory returns run_time and run_duration as INTEGER value formatted as HHMMSS.
How to convert it to seconds?
Example:
163135 (16:31:35) becomes 59495 (seconds)
Meanwhile I figured out this formula:
SELECT DATEDIFF(SECOND, '00:00:00', FORMAT(run_duration, '00:00:00'))
FROM msdb.dbo.sysjobhistory
You can use modulo and integer division to separate the hours, minutes, and seconds, multiply by number of seconds in each result, then sum.
DECLARE #hms int = 163135;
SELECT #hms / 10000 * 3600
+ #hms % 10000 / 100 * 60
+ #hms % 100;
59495
To use this as a view, it's really not any different:
CREATE VIEW dbo.viewname
AS
SELECT <other cols>, run_duration,
run_duration_s = run_duration / 10000 * 3600
+ run_duration % 10000 / 100 * 60
+ run_duration % 100
FROM msdb.dbo.sysjobhistory
WHERE ...
If you don't like math so much, you can treat it like a string:
DECLARE #hms int = 163135;
DECLARE #s char(6) = RIGHT(CONCAT('000000', #hms), 6);
SELECT LEFT(#s, 2) * 60 * 60
+ SUBSTRING(#s, 3, 2) * 60
+ RIGHT(#s, 2);
59495
However, this latter solution may need some tweaking if you could have durations > 99 hours, since now the string will be 7 digits. Maybe safer to use:
DECLARE #hms int = 163135;
DECLARE #s char(24) = RIGHT(CONCAT(REPLICATE('0',24), #hms), 24);
SELECT LEFT(#s, 20) * 60 * 60
+ SUBSTRING(#s, 21, 2) * 60
+ RIGHT(#s, 2);
24 is a ludicrous example, but safe. The job would have had to start in 1990 to hit 10 digits today.

Calculating Early and Late Dates for Performance Measurement

I am trying to calculate shipping performance in SSMS- Im getting stuck in several areas and I hope i can get some help!
I have an Estimated Ship Date, an Appt Date, and an Actual Ship date.
Im measuring warehouse performance, so in most cases shipments leave same day. But in others, they may leave a few days early or late.
The problem that i am having is the correct output. I want to show the Values in DD:HH:MM, but the syntax for DateDiff doesn't give me an accurate day to use:
For Example, a shipment was supposed to leave on 6/3/2019 # at 8 am, but didnt leave the warehouse until 7/22/2019 # 6:30 AM. In this case, DateDiff calcs 49 days, when really its 48 days 22 hours and 30 minutes late. Here is an example of some of the syntax i am using:
EstimatedShipDate datetime,
AppointmentShipDate datetime,
ActualShipDate datetime
);
insert into #test values ('2019-07-01 11:00', '2019-07-01 11:00','2019-06-30 10:30');
insert into #test values ('2019-07-08 13:45', null,'2019-07-01 22:00');
insert into #test values ('2019-07-09 15:00', null,'2019-07-10 15:00');
insert into #test values ('2019-07-03 15:00', null,'2019-07-04 15:00');
insert into #test values ('2019-07-08 15:00', null,'2019-07-08 15:00');
insert into #test values ('2019-07-08 15:00', null,'2019-07-08 22:00');
insert into #test values ('2019-07-03 08:00', null,'2019-07-04 15:00');
insert into #test values ('2019-07-03 08:00', null,'2019-07-03 06:30');
insert into #test values ('2019-06-03 08:00', null,'2019-07-22 06:30');
insert into #test values ('2019-07-01 11:00', null,'2019-06-29 10:30');
Select
EstimatedShipDate,
AppointmentShipDate,
ActualShipDate,
DATEDIFF(DAY,ISNULL(CAST(AppointmentShipDate as DateTime),CAST(EstimatedShipDate as DateTime)), CAST(ActualShipDate as DateTime)) as Days,
DATEPART(DAY, ISNULL(CAST(AppointmentShipDate as DateTime),CAST(EstimatedShipDate as DateTime))-CAST(ActualShipDate as DateTime) ) as days2,
DATEDIFF(Hour,ISNULL(CAST(AppointmentShipDate as DateTime),CAST(EstimatedShipDate as DateTime)), CAST(ActualShipDate as DateTime)) as Hours,
convert(varchar, CAST(ActualShipDate as DateTime)-ISNULL(CAST(AppointmentShipDate as DateTime),CAST(EstimatedShipDate as DateTime)),108) as DateSubtract_Convert,
convert(varchar,ISNULL(CAST(AppointmentShipDate as DateTime),CAST(EstimatedShipDate as DateTime)-CAST(ActualShipDate as DateTime) ),108) as DateSubtract_ConvertEarly
from #TEST
In this case, DateDiff calcs 49 days, when really its 48 days 22 hours and 30 minutes late. Or vice versa, I have a date range that shows 2 days 23:20 but it should be 1 day 23:20
One way is to increase granularity of DATEDIFF to MINUTE. That will require calculation for the days, hours, and minutes using the minutes (division and mod).
SELECT ABS(dT.diff_Minutes / 1440) AS [Days] --days, there are 1440 minutes in a day
,ABS((dT.diff_Minutes % 1440) / 60) AS [Hours] --hours remaining in the day
,ABS((dT.diff_Minutes % 1440) % 60) AS [Minutes] --minutes remaining in the day
FROM (
SELECT DATEDIFF(MINUTE, ISNULL(AppointmentShipDate, EstimatedShipDate), ActualShipDate) [diff_Minutes]
FROM #test
) AS dT
Your temp table produces output:
Days Hours Minutes
1 0 30
6 15 45
1 0 0
1 0 0
0 0 0
0 7 0
1 7 0
0 1 30
48 22 30
2 0 30
To put these in DD:HH:MM format is more complicated, but you can cast the numbers to varchar and concatenate as strings. RIGHT is used to add any leading zeroes.
SELECT CASE WHEN dT.diff_Minutes < 0 THEN '- ' ELSE '+ ' END --positive or negative
+ RIGHT('00' + CAST(ABS(dT.diff_Minutes / 1440) as varchar(1000)), 2)
+ ':'
+RIGHT('00' + CAST((ABS(dT.diff_Minutes % 1440) / 60) as varchar(2)), 2)
+ ':'
+RIGHT('00' + CAST((ABS(dT.diff_Minutes % 1440) % 60) as varchar(2)), 2)
AS [DD:HH:MM]
FROM (
SELECT DATEDIFF(MINUTE, ISNULL(AppointmentShipDate, EstimatedShipDate), ActualShipDate) [diff_Minutes]
FROM #test
) AS dT
Produces output:
DD:HH:MM
- 01:00:30
- 06:15:45
+ 01:00:00
+ 01:00:00
+ 00:00:00
+ 00:07:00
+ 01:07:00
- 00:01:30
+ 48:22:30
- 02:00:30
Use seconds instead of days and then do a little math with seconds, minutes and hours.
Here's a simple SSMS example:
DECLARE
#ScheduledDate DATETIME = '6/3/2019 08:00:00',
#ShippedDate DATETIME = '07/22/2019 06:30:00';
SELECT
CONVERT( VARCHAR, DATEDIFF( s, #ScheduledDate, #ShippedDate ) /60/60/24 ) + ' Days and '
+ CONVERT( VARCHAR, ( #ShippedDate - #ScheduledDate ), 108 ) + ' Hours.';
Returns
48 Days and 22:30:00 Hours.

how to use sql to get number of seconds from a string formatted like "HH:MM:SS"

I have a C# program that recorded a TimeSpan value into a SQL Server table's varchar field. For example, the varchar field might have the value "00:12:05.7989790".
How could I use SQL code to get that total value in SECONDS? Since that varchar represents 12 minutes and 5 seconds, I would like a SQL statement that extracts it as "725".
I've tried some code like this:
select
Case when IsDate(the_value)=1 then datepart(HOUR, CONVERT(datetime, the_value))*360 else 0 end
+ Case when IsDate(the_value)=1 then datepart(MINUTE, CONVERT(datetime, the_value))*60 else 0 end
+ Case when IsDate(the_value)=1 then datepart(SECOND, CONVERT(datetime, the_value))*1 else 0 end
from mytable
but it complains "Conversion failed when converting date and/or time from character string."
Any suggestions would be greatly appreciated.
DATEDIFF function
https://msdn.microsoft.com/en-AU/library/ms189794.aspx
DATEDIFF(ss, '00:00:00.000', [your time column])
I would use datediff() and use explicit conversion to time:
select datediff(second, '00:00:00', convert(time, the_value))
If the units can exceed 23 hours, then you have a challenge, because the conversion will fail. In this case, string manipulation is an option:
select (left(the_value, 2) * 60 * 60 +
substring(the_value, 3, 2) * 60 +
substring(the_value, 5, 2)
) as seconds
This assumes that all strings are in the proper format. You can validate this with a case:
select (case when the_value like '[0-9]0-9]:[0-9[0-9]:[0-9][0-9]%'
then (left(the_value, 2) * 60 * 60 +
substring(the_value, 3, 2) * 60 +
substring(the_value, 5, 2)
)
end) as seconds

Operand type clash: time is incompatible with int

In a table, I have a column (AvgWaitTime) which stores data value in seconds (Data Type: float), date wise. I have a function which performs some calculation using AvgWaitTime column and other few columns and returns a value in time format. I would to convert the value returned by the function (time format) into seconds (preferrably decimal, if not then int).
select
(datepart(HH, dbo.fnGetMonthlyAverageWaitTime(m.RDate) * 60 * 60) +
datepart(mi, dbo.fnGetMonthlyAverageWaitTime(m.RDate) * 60) +
datepart(s, dbo.fnGetMonthlyAverageWaitTime(m.RDate)))[MonthlyAverageWaitTime]
from TelephonyMTD m
Error: Operand type clash: time is incompatible with int
So, I tried to run this:
select
(datepart(HH, GetDate() * 60 * 60) +
datepart(mi, GetDate() * 60) +
datepart(s, GetDate()))
Now it says, Implicit conversion from data type datetime to int is not allowed. Use the CONVERT function to run this query. Which is true when I looked at the data type conversion chart, I came to know that conversion to int and float is now allowed.
Please advice.
The problem is you are trying to multiply a date/datetime by an integer which doesn't make sense:
GetDate() * 60 * 60
You could simply use DATEDIFF with seconds, to get the value in seconds:
SELECT DATEDIFF(SECOND, '00:00:00', dbo.fnGetMonthlyAverageWaitTime(m.RDate)) AS MonthlyAverageWaitTime
FROM TelephonyMTD AS m
QUICK EXAMPLE
SELECT t.AvgTime,
AvgTimeInSeconds = DATEDIFF(SECOND, '00:00:00', t.AvgTime)
FROM (VALUES
(CAST('00:01:15' AS TIME)),
(CAST('05:36:47' AS TIME))
) AS t (AvgTime);
Which gives:
+----------+------------------+
| AvgTime | AvgTimeInSeconds |
+----------+------------------+
| 00:01:15 | 75 |
| 05:36:47 | 20207 |
+----------+------------------+
Open and Close brackets are the one causing issue for the above error: Please try like below
SELECT (
( Datepart(HH, Getdate()) * 60 * 60 ) +
( Datepart(mi, Getdate()) * 60 ) +
Datepart(s, Getdate())
)
Try to use Below Syntax to convert seconds to day, hour, minute, seconds
DECLARE #sec INT = 86400;
SELECT
CAST(#sec /60/60/24 AS VARCHAR(12)) + ' Days,'
+ CAST(#sec /60/60 % 24 AS VARCHAR(12))+ ' Hours,'
+ CAST(#sec /60 % 60 AS VARCHAR(2)) + ' Minutes, '
+ CAST(#sec % 60 AS VARCHAR(2)) + ' Seconds.';

Cannot get hours to total over 24, eg 48 hours in hh:mm:ss output

I am running a query to find out the total amount of time a user has been browsing for. Each browsing session is stored in the DB as seconds and I then sum the total seconds and convert it into hh:mm:ss. The problem is when I'm converting the seconds into hh:mm:ss. I want it to display for example '78:20:00' but I dont know how to get the code to total it like this. When it gets past 24 hrs the hrs column goes back to 00 because its into a day.
The query I run to convert the time can be seen below:
SELECT Username,
CONVERT(VARCHAR(12),DATEADD(SECOND,TotalTimeInSeconds,0),108) AS TotalHours
FROM #TotalSessionTime
SELECT USERNAME,
CAST(TotalTimeInSeconds / (60 * 60) AS Varchar) + ':' +
CAST(TotalTimeInSeconds % (60 * 60) / 60 AS Varchar) + ':' +
CAST(TotalTimeInSeconds % (60) AS Varchar) AS TotalHours
FROM #TotalSessionTime
If you want minutes and seconds to always be two digits, you'll have to left pad them, which would make for an ugly example, but would work fine.
Try this...
DECLARE #TimeInSeconds int = 123400;
DECLARE #MyDate datetime;
SELECT #MyDate = CONVERT( DateTime, DATEADD( SECOND, #TimeInSeconds, 0))
SELECT CONVERT(CHAR(2), (DAY( #MyDate )-1) * 24 + DATEPART(hour,#MyDate)) + ':' + CONVERT(CHAR(2), DATEPART(minute, #MyDate)) + ':' + CONVERT(CHAR(2), DATEPART(SECOND, #MyDate))
You'll want to left-pad the minutes and seconds with a zero to be sure it's 2-digits, though.

Resources