SQL Server : conversion failed when converting date and/or time from character with string past 12pm - sql

For the past few days my code has worked, but today it has the following error:
Conversion failed when converting date and/or time from character string
Here is my code:
DECLARE #run_time INT
DECLARE #run_duration INT
SET #run_time = '120609'
SET #run_duration = '2600'
SELECT
h.step_id,
CAST(j.[name] AS VARCHAR) as JobName,
h.step_name,
CAST(REPLACE(LEFT(CAST(case
when len(#run_time) = 1 then '00:00:0' + cast(#run_time as varchar)
when len(#run_time) = 2 then '00:00:' + cast(#run_time as varchar)
when len(#run_time) = 3 then '00:0' + cast(left(#run_time,1) as varchar) + ':' + cast(right(#run_time,2) as varchar)
when len(#run_time) = 4 then '00:' + cast(left(#run_time,2) as varchar) + ':' + cast(right(#run_time,2) as varchar)
when len(#run_time) = 5 then '0' + cast(left(#run_time,1) as varchar) + ':' + SUBSTRING(CAST(#run_time AS VARCHAR), 2, 2) + ':' + SUBSTRING(CAST(#run_time AS VARCHAR), 4,2)
when len(#run_time) = 6 then cast(left(#run_time,2) as varchar) + ':' + SUBSTRING(CAST(#run_time AS VARCHAR), 2,2) + ':' + SUBSTRING(CAST(#run_time AS VARCHAR), 4,2)
END AS TIME), 8), ':', '') AS INT) StartTime
I discovered the only time the error appears is when the run_time goes past 120000 (12pm), hence why I've never noticed it before because the agent jobs have ran at 3am. It shouldn't be an issue in the future, but just in case it is I would like a fix for this. I can't find an example anywhere that's similar to my code. Unfortunately casting the results like this is the only way I can get a graph in SSRS to work. (INT > VARCHAR > TIME > INT).
edit - here is a better example of my code using one of the proposed answers:
SELECT
h.step_id,
CAST(j.[name] AS VARCHAR) as JobName,
h.step_name,
CAST(stuff(stuff(right('0000000' + h.run_time, 6), 5, 0, ':'), 3, 0, ':') as time)
FROM
msdb.dbo.sysjobs j
INNER JOIN msdb.dbo.sysjobhistory h ON j.job_id = h.job_id
Thanks,

If you are trying to calculate the start time from a string in HHMMSS format, then this method seems much simpler to me:
select cast(stuff(stuff(right('0000000' + str, 6), 5, 0, ':'), 3, 0, ':') as time)
from (values ('120609'), ('0'), ('1001')) v(str)

In your case the problem is the string which you are trying to convert: "12:20:60"
The converstion to TIME type fails.
DECLARE #run_time INT
DECLARE #run_duration INT
SET #run_time = '120609'
SET #run_duration = '2600'
SELECT
-- h.step_id,
--CAST(j.[name] AS VARCHAR) as JobName,
-- h.step_name,
--CAST(REPLACE(LEFT(CAST(
case
when len(#run_time) = 1 then '00:00:0' + cast(#run_time as varchar)
when len(#run_time) = 2 then '00:00:' + cast(#run_time as varchar)
when len(#run_time) = 3 then '00:0' + cast(left(#run_time,1) as varchar) + ':' + cast(right(#run_time,2) as varchar)
when len(#run_time) = 4 then '00:' + cast(left(#run_time,2) as varchar) + ':' + cast(right(#run_time,2) as varchar)
when len(#run_time) = 5 then '0' + cast(left(#run_time,1) as varchar) + ':' + SUBSTRING(CAST(#run_time AS VARCHAR), 2,2) + ':' + SUBSTRING(CAST(#run_time AS VARCHAR), 4,2)
when len(#run_time) = 6 then cast(left(#run_time,2) as varchar) + ':' + SUBSTRING(CAST(#run_time AS VARCHAR), 2,2) + ':' + SUBSTRING(CAST(#run_time AS VARCHAR), 4,2)
END ,
SUBSTRING(CAST(#run_time AS VARCHAR), 4,2)
--AS TIME)
--,8), ':', '') AS INT) StartTime
Did you check this out?
How to convert an integer (time) to HH:MM:SS::00 in SQL Server 2008?
The best solution should be the one proposed by Gordon

This works for me:
SELECT
h.step_id,
CAST(j.[name] AS VARCHAR) as JobName,
h.step_name,
-- CAST(stuff(stuff(right('0000000' + h.run_time, 6), 5, 0, ':'), 3, 0, ':') as time)
(h.run_time / 1000000) % 100 as hour,
(h.run_time / 10000) % 100 as minute,
(h.run_time / 100) % 100 as second,
(h.run_time % 100) * 10 as millisecond,
dateadd(hour, (h.run_time / 1000000) % 100, dateadd(minute, (h.run_time / 10000) % 100, dateadd(second, (h.run_time / 100) % 100, dateadd(millisecond, (h.run_time % 100) * 10, cast('00:00:00' as time(2))))))
FROM
msdb.dbo.sysjobs j
INNER JOIN msdb.dbo.sysjobhistory h ON j.job_id = h.job_id
Btw, the CAST drives to error for me, as well
In case you don't want to use the select statement:
DECLARE #run_time INT
DECLARE #time_result TIME
SET #run_time = '120609'
SET #time_result = dateadd(hour, (#run_time / 1000000) % 100, dateadd(minute, (#run_time / 10000) % 100, dateadd(second, (#run_time / 100) % 100, dateadd(millisecond, (#run_time % 100) * 10, cast('00:00:00' as time(2))))))
select #time_result

Related

Query to calculate sum of time with above 24 hours interval

I have time like 25:00:00, 10:00:00, 30:00:00 and I want to calculate the sum of the values from database. How can I do that the current query for calculating sum is
SQL query:
SELECT
CAST(FORMAT((SUM((DATEPART("ss", Total_Time) +
DATEPART("mi", Total_Time) * 60 +
DATEPART("hh", Total_Time) * 3600)) / 3600), '00') AS varchar(max)) + ':' + CAST(FORMAT((SUM((DATEPART("ss", Total_Time) + DATEPART("mi", Total_Time) * 60 + DATEPART("hh", Total_Time) * 3600)) % 3600 / 60), '00') as varchar(max)) + ':' +CAST(FORMAT((SUM((DATEPART("ss", Total_Time) + DATEPART("mi", Total_Time) * 60 + DATEPART("hh", Total_Time) * 3600)) % 3600 % 60), '00') as varchar(max)) as WorkingTimeSum
FROM
tasker_usr.TaskTime
but I get an error
Cannot convert from datetime to character string
You cannot fit your values into a time datatype. It stores only value less than 23:59:59.9999999. Hence you cannot use DATEPART or DATEDIFF directly. One way is to split your values(as seconds) and do the sum. Something like
WITH CTE_SUM
AS (
SELECT SUM(LEFT(column_name, 2) * 3600
+ SUBSTRING(column_name, 4, 2) * 60
+ SUBSTRING(column_name, 7, 2)) AS SUM_AS_SECONDS
FROM YOUR_TABLE
)
SELECT CAST(SUM_AS_SECONDS / 3600 AS VARCHAR) + ':'
+ CAST(SUM_AS_SECONDS % 3600 / 60 AS VARCHAR) + ':'
+ CAST(((SUM_AS_SECONDS % 3600) % 60) AS VARCHAR) AS WorkingTimeSum
FROM CTE_SUM
Please note that this will work upto 99:99:99.If you have time values that are more than that, then you have to split based on : instead of hardcoding values in LEFT/Substring
Are you looking something like this ?
Declare #Hours Table(Hrs VARCHAR(20))
Declare #Hour TINYINT, #Minute INT,#Second INT, #InSeconds BIGINT, #Cdate DATETIME
INSERT #Hours
SELECT '25:00:00' Union All
SELECT '10:00:00' Union All
SELECT '30:00:00'
select #Hour = sum(cast(Left(Hrs,CharIndex(':',Hrs,1)-1) as int)) from #Hours
select #Minute = sum(cast(Substring(Hrs,CharIndex(':',Hrs,1)+1,2)as int)) from #Hours
select #Second = sum(cast(Substring(Hrs,CharIndex(':',Hrs,1)+4,2)as int)) from #Hours
Set #InSeconds = #Second + (#Minute * 60) + (#Hour *60 *60)
Set #Cdate = dateadd(second,#InSeconds,0)
select datediff(day,'1900-01-01',#Cdate) [Day(s)],
Format(#Cdate,'hh') [Hour(s)],
Format(#Cdate,'mm') [Minute(s)],
Format(#Cdate,'ss') [Second(s)]
Day(s)
Hour(s)
Minute(s)
Second(s)
2
05
00
00
Assuming that your format is HH(n):MM:SS (that is, hours can have 1 or more digits), you can decompose the value and reconstruct it. This requires string functions. You can get the total seconds as:
select sum(left(total_time, charindex(':', total_time) - 1) * 60 * 60 +
left(right(total_time, 5), 2) * 60 +
right(total_time, 2)
) as total_secs
from tasker_usr.TaskTime;
Note: This does implicit conversion from the string values to integers, but that should be okay if your values are consistent.
You can convert back to string:
select concat(format(total_secs / (60 * 60), '00:'),
format( (total_secs / 60) % 60, '00:'),
format(total_secs % 60, '00')
) as time_format
from (select sum(left(total_time, charindex(':', total_time) - 1) * 60 * 60 +
left(right(total_time, 5), 2) * 60 +
right(total_time, 2)
) as total_secs
from tasker_usr.TaskTime
) t

Convert SUM of integer to HH:MM format

I have time stored in minutes in integer datatype which has to be displayed in HH:MM format. For example: if total minutes is 80 then it should convert to 01:20.
select SUM(OTTime) from dbo.TableOT where ....
I have tried some queries but didn't get the exact output.
Updated Query:
SELECT SUM(t.OTTime),d.combovalue
FROM dbo.employee e
join dbo.OT t
on e.id = t.employeeid
JOIN dbo.combovalues d
ON e.department = d.id
GROUP By d.combovalue
Try this Single Query:
DECLARE #Duration int
SET #Duration= 4000
SELECT CAST( CAST((#Duration) AS int) / 60 AS varchar) + ':' + right('0' + CAST(CAST((#Duration) AS int) % 60 AS varchar(2)),2)
For Updated Query:
SELECT d.combovalue,CAST(CAST((SUM(t.OTTime)) AS int) / 60 AS varchar) + ':'
+ right('0' + CAST(CAST((SUM(t.OTTime)) AS int) % 60 AS varchar(2)),2)
FROM dbo.employee e join dbo.OT t on e.id = t.employeeid
JOIN dbo.combovalues d ON e.department = d.id
GROUP By d.combovalue
Instead of #minutes variable you can use SUM(OTTime) and a from clause in this below Query
DECLARE #minutes INT=80
SELECT CASE WHEN #minutes >= 60 THEN (SELECT CAST((#minutes / 60) AS VARCHAR(2)) + ':' + CASE WHEN (#minutes % 60) > 0 THEN CAST((#minutes % 60) AS VARCHAR(2))
ELSE '' END)
ELSE CAST((#minutes % 60) AS VARCHAR(2)) END
For Eg:
SELECT CASE WHEN SUM(OTTime) >= 60 THEN (SELECT CAST((SUM(OTTime) / 60) AS VARCHAR(2)) + ':' + CASE WHEN (SUM(OTTime) % 60) > 0 THEN CAST((SUM(OTTime) % 60) AS VARCHAR(2))
ELSE '' END)
ELSE CAST((SUM(OTTime) % 60) AS VARCHAR(2)) END
from dbo.TableOT where ....
Create a SCALAR Function and pass the
select dbo.Minutes_to_HrsMts (SUM(OTTime)) from dbo.TableOT where ....
Function:
CREATE Function dbo.Minutes_to_HrsMts (#minutes INT)
RETURNS nvarchar(30)
AS
BEGIN
declare #hours nvarchar(20)
SET #hours =
CASE WHEN #minutes >= 60 THEN
(SELECT CAST((#minutes / 60) AS VARCHAR(2)) + ':' +
CASE WHEN (#minutes % 60) > 0 THEN
CAST((#minutes % 60) AS VARCHAR(2))
ELSE
''
END)
ELSE
CAST((#minutes % 60) AS VARCHAR(2))
END
return #hours
END
First, I recommend using decimal hours. Much simpler:
SELECT d.combovalue, SUM(t.OTTime) / 60.0
FROM dbo.employee e JOIN
dbo.OT t
ON e.id = t.employeeid JOIN
dbo.combovalues d
ON e.department = d.id
GROUP By d.combovalue;
But that is not your question. If you knew that there are never more than 24 hours, you could use the TIME data type:
CONVERT(VARCHAR(5), DATEADD(minute, SUM(t.OTTime), 0), 8)
If that is too dangerous, then you need to convert to a string:
CONCAT(FORMAT(SUM(t.OTTime) / 60, '00'), ':', FORMAT(SUM(t.OTTime) % 60, '00'))

Convert from bigint to time only

I have big-int data, and I want to convert it from Big-int to just time, for example I have this value 53006745 for ' 14hrs 43min '
Please help me to write the query in SQL Server, so that will convert big-int into minutes.
If You're looking Pure Time you could try below SQL Query which will give Minutes from Your Integer Value:
DECLARE #value INT = 53006745
SELECT DATEPART(MINUTE, DATEADD(s, CONVERT(BIGINT, #value) / 1000, CONVERT(DATETIME, '1-1-2017 00:00:00'))) [Minutes];
Result :
Minutes
43
You can use this code for yourself in SQL :
SELECT DATEADD(s, CONVERT(BIGINT, 53006745 ) / 1000,
CONVERT(DATETIME,
'1-1-1970 00:00:00'))
This code return 1970-01-01 14:43:26.000 as you like
DECLARE #Value INT = 53006745
SELECT
CONVERT(VARCHAR, #Value/3600000) + ':' -- Hours
+ RIGHT('0' + CONVERT(VARCHAR, #Value%3600000/60000), 2) + ':' -- Minutes
+ RIGHT('0' + CONVERT(VARCHAR, #Value%3600000%60000/1000), 2) + '.' -- Seconds
+ RIGHT('00' + CONVERT(VARCHAR, #Value%1000), 3) -- Milliseconds

Minutes to hh:mm format in SQL Server 2008 query

I have a column Time in my table. It holds a time value in minutes, ie: 605. What I want it to show it as 10:05, as hh:mm format.
I am doing it like this:
...
Time = cast(AVG(Time) / 60 as varchar) + ':' + cast(AVG(Time) % 60 as varchar),
...
It shows the value as 10:5, but I want to make it as 10:05 and I couldn't find out a way to add '0' before '5' in the minutes section.
Any help would be appreciated.
Try this:
SELECT
TIME = CASE WHEN #t < 600 THEN '0' ELSE '' END +
CAST(Time / 60 as varchar(10)) + ':' +RIGHT(100 +(Time % 60), 2)
Example:
DECLARE #t int = 55121
SELECT
TIME = CASE WHEN #t < 600 THEN '0' ELSE '' END +
CAST(#t / 60 as varchar(10)) + ':' +RIGHT(100 +(#t % 60), 2)
Result:
Time
918:41
You could simply add a Right('0' + ...,2) expression as below to get the '0' in there.
Time = cast(AVG(Time) / 60 as varchar) + ':' + RIGHT('0'+cast(AVG(Time) % 60 as varchar),2)
To answer your question in comments, getting DD:HH:MM is a similar setup.
DayTime = cast(AVG(Time) / 1440 as varchar) + ':' + RIGHT('0' + cast((AVG(Time) / 60) % 24 as varchar),2) + ':' + RIGHT('0'+cast(AVG(Time) % 60 as varchar),2)
You can use a case expression to do this.
Also you should always specify the length of varchar when you use cast, or it would only show the first character.
case when len(cast(AVG(Time)%60 as varchar(2))) < 2 then '0'+cast(AVG(Time)%60 as varchar(2))
else cast(AVG(Time)%60 as varchar(2))
end

if minute is less than 60 then remove hour part from result

I have a function like this:
ALTER FUNCTION [dbo].[testfunctionstacknew] (#dec NUMERIC(18, 2)) RETURNS Varchar(50)
AS
BEGIN
DECLARE
#hour decimal(18,2),
#Mns decimal(18,2),
#second decimal(18,3)
DECLARE #Average Varchar(50)
select #hour=CONVERT(int,#dec/60/60)
SELECT #Mns = convert(int, (#dec / 60) - (#hour * 60 ));
select #second=#dec % 60;
SELECT #Average =
convert(varchar(9), convert(int, #hour)) + ':' +
-- right('00' + convert(decimal(10,0), convert(decimal(18,2), #hour)), 2) + ':' +
right('00' + convert(decimal(10,0), convert(decimal(18,2), #Mns)), 2) + ':' +
right('00' + CONVERT(decimal(10,0), convert(varchar(10), #second)), 6)
RETURN #Average
END
and i have a stored procedure like this:
select dbo.testfunctionstacknew(
convert(decimal(10,1),
avg(convert(numeric(18,2), datediff(ss, t.dtime, t.PAICdate ))))
) as Avgparkingtime from (select top 10 * from transaction_tbl where locid=6 and dtime >= getdate()-1 order by transactID desc ) t
while executing stored procedure if the average time is less than 60 minutes i am getting result like this:
Avgparkingtime :
0:25:33
if the average time is less than 60 minutes then i dont want to get zero in front of minutes,,(this time only need to show minutes and seconds)..only hour need to show if the minutes is greater than 60 minutes...how i can do this? what changes i have to make in my function ?? any help is very appreciable..
Try changing the part where you build the formatted string like this:
SELECT #Average =
case
when convert(int, #hour) <> 0 then convert(varchar(9), convert(int, #hour)) + ':'
else ''
end +
right('00' + convert(decimal(10,0), convert(decimal(18,2), #Mns)), 2) + ':' +
right('00' + CONVERT(decimal(10,0), convert(varchar(10), #second)), 6)