Calculate Salesforce Case response time - salesforce

I'm new with salesforce formula and I have this requirement to compute the business hours with mins. in salesforce.
what i did is that i set-up one field in case objects (data type = formula).
and i applied the formula below. it's working however I cannot get accurate minutes value.
Case 1: I'm getting 2,088.00 but if via manual computation i should get 2088.25
Date/Time Opened
LastModifiedDate
5/24/2021 4:45 PM
4/13/2022 5:10 PM
Case 2: I'm getting 0 as result but if via manual computation i should get 0.11
Date/Time Opened
LastModifiedDate
11/22/2022 11:38 AM
11/22/2022 11:49 AM
Based from some articles salesforce is in GMT so what i did is i get the equivalent of 08:30 SGT to GMT which in this case 12:30 (if my understanding is correct)
Formula:
ROUND( 9 * (
( 5 * FLOOR( ( DATEVALUE( LastModifiedDate) - DATE( 1900, 1, 8) ) /
7) +
MIN(5,
MOD( DATEVALUE( LastModifiedDate ) - DATE( 1900, 1, 8), 7) +
MIN( 1, 24 / 8 * ( MOD( LastModifiedDate - DATETIMEVALUE( '1900-01-08 12:30:00' ), 1 ) ) )
)
)
-
( 5 * FLOOR( ( DATEVALUE( CreatedDate) - DATE( 1900, 1, 8) ) /
7) +
MIN( 5,
MOD( DATEVALUE( CreatedDate ) - DATE( 1996, 1, 1), 7 ) +
MIN( 1, 24 / 8 * ( MOD( CreatedDate - DATETIMEVALUE( '1900-01-08 12:30:00' ), 1) ) )
)
)
),2
)
Thank you in advance for your help..

Related

Salesforce business hours calculation on start and end date

I am trying to calculate difference between to dates in formula field on start and end date. I am not getting accurate value.
I should calculate hours in weekdays that is Monday to Friday and 9 AM to 6 PM EST between given dates
below is my formula:
ROUND( 9 * (
( 5 * FLOOR( ( DATEVALUE( End_Date_Time__c ) - DATE( 1900, 1, 8) ) / 7) +
MIN(5,
MOD( DATEVALUE( End_Date_Time__c ) - DATE( 1900, 1, 8), 7) +
MIN( 1, 24 / 9 * ( MOD( End_Date_Time__c - DATETIMEVALUE( '1900-01-08 14:00:00' ), 1 ) ) )
)
)
-
( 5 * FLOOR( ( DATEVALUE( Start_Date_Time__c ) - DATE( 1900, 1, 8) ) / 7) +
MIN( 5,
MOD( DATEVALUE( Start_Date_Time__c ) - DATE( 1996, 1, 1), 7 ) +
MIN( 1, 24 / 9 * ( MOD( Start_Date_Time__c - DATETIMEVALUE( '1900-01-08 14:00:00' ), 1) ) )
)
)
),
0 )
In some scenarios I am getting expected results but in most not correct values.

Can't convert time to mm:ss

I have a table with 7 columns:
Start_hour | Start_minute | Start_second | End_hour | End_minute | end_second | date
My task is to sum the differences between start and end times on current day. And my query already does that. Sadly I need the output to be in minutes:seconds only. For Example the total sum of time differences is 2 hour 26 minutes and 52 seconds.
I need my output to like this:
126:52
My query right now looks like this:
SELECT
RIGHT(CONVERT(CHAR(8),
DATEADD(SECOND,
SUM(DATEDIFF(SECOND,
Timefromparts(start_hour, start_minute, start_second, 0, 0),
Timefromparts(end_hour, end_minute, end_second, 0, 0))
), 0), 108), 5)
FROM
opoznienia
WHERE
YEAR(data) = YEAR(GETDATE())
AND MONTH(data) = MONTH(GETDATE())
AND DAY(data) = DAY(GETDATE())
Sample data:
Start_hour | Start_minute | Start_second | End_hour | End_minute | end_second | date
10 15 0 10 30 30 2018-11-27 14:40:53.680
10 15 0 10 30 30 2018-11-30 10:16:20.610
6 10 30 6 23 45 2018-12-02 01:00:27.243
8 10 0 8 53 45 2018-12-02 14:42:48.663
10 5 13 10 55 23 2018-12-02 14:53:03.560
Output of the query above:
47:13 (without RIGHT command it would be 01:47:13)
The wanted output:
107:13
You need to calculate the number of seconds and then format it as you want. From number of seconds you can calculate the minutes as division by 60, where the remainder are the seconds:
declare #NumberOfSeconds int = 7612
-- Returns 126:52
select concat(#NumberOfSeconds / 60, ':', FORMAT(#NumberOfSeconds % 60, 'D2'))
Here is one option:
SELECT
numSeconds,
CASE WHEN numSeconds / 60 <= 100
THEN RIGHT('00' + CONVERT(VARCHAR(20), numSeconds / 60), 2)
ELSE CONVERT(VARCHAR(20), numSeconds / 60) END
+ ':' +
CASE WHEN numSeconds / 60 <= 100
THEN RIGHT('00' + CONVERT(VARCHAR(20), numSeconds % 60), 2)
ELSE CONVERT(VARCHAR(20), numSeconds % 60) END AS output
FROM yourTable;
Demo
The ugliness in the code has to do with that you expect a minimum of two digits for the minute and second components. So, we have to pad each component with zeroes in the case where minutes or seconds happens to be just a single digit.
The other answers are better, but to understand what may be missing in what you're trying to do - you can look at following where DatePart is used.
-->"
..(without RIGHT command it would be 01:47:13)
" This is your clue that you that you need to work with the parts and not the whole...
SELECT Cast
(
Datepart
(
hour,
DATEADD(second,sum(datediff(second,
TIMEFROMPARTS ( Start_hour, Start_minute, Start_second, 0, 0),
TIMEFROMPARTS ( End_hour, End_minute, End_second, 0, 0))),0)
) * 60
+
Datepart
(
minute,
DATEADD(second,sum(datediff(second,
TIMEFROMPARTS ( Start_hour, Start_minute, Start_second, 0, 0),
TIMEFROMPARTS ( End_hour, End_minute, End_second, 0, 0))),0)
) As varchar)
+
':'
+
Cast
(
Datepart
(
second,
DATEADD(second,sum(datediff(second,
TIMEFROMPARTS ( Start_hour, Start_minute, Start_second, 0, 0),
TIMEFROMPARTS ( End_hour, End_minute, End_second, 0, 0))),0)
) As varchar) as result
from minsec
Try the following
CREATE TABLE T(
StartHour INT,
StartMinute INT,
StartSecond INT,
EndHour INT,
EndMinute INT,
EndSecond INT,
[Date] DATE
);
INSERT INTO T VALUES
(10, 15, 0 , 10, 30, 30, '2018-11-27'),
(10, 15, 0 , 10, 30, 30, '2018-11-30'),
(6 , 10, 30, 6 , 23, 45, '2018-12-02'),
(8 , 10, 0 , 8 , 53, 45, '2018-12-02'),
(10, 5 , 13, 10, 55, 23, '2018-12-02');
SELECT *,
CAST( (DATEDIFF(Hour, StartTime, EndTime) * 60) +
(DATEDIFF(Minute, StartTime, EndTime) % 60) AS VARCHAR
) + ':' +
CAST(DATEDIFF(Second, StartTime, EndTime) % 60 AS VARCHAR)
FROM
(
SELECT [Date],
TIMEFROMPARTS(StartHour, StartMinute, StartSecond, 0, 0) StartTime,
TIMEFROMPARTS(EndHour, EndMinute, EndSecond, 0, 0) EndTime
FROM T
) TT
You can also SUM() and GROUP BY [Date] if you want to.
SELECT [Date],
CAST( SUM( (DATEDIFF(Hour, StartTime, EndTime) * 60) +
(DATEDIFF(Minute, StartTime, EndTime) % 60)
) AS VARCHAR
) + ':' +
CAST(SUM(DATEDIFF(Second, StartTime, EndTime) % 60) AS VARCHAR)
FROM
(
SELECT [Date],
TIMEFROMPARTS(StartHour, StartMinute, StartSecond, 0, 0) StartTime,
TIMEFROMPARTS(EndHour, EndMinute, EndSecond, 0, 0) EndTime
FROM T
) TT
GROUP BY [Date]
Demo
UPDATE
It seems like you are looking for
SELECT [Date],
CAST(SUM(DATEDIFF(Second, StartTime, EndTime)) / 60 AS VARCHAR) + ':' +
CAST(SUM(DATEDIFF(Second, StartTime, EndTime)) % 60 AS VARCHAR) [MM:SS]
FROM
(
SELECT [Date],
TIMEFROMPARTS(StartHour, StartMinute, StartSecond, 0, 0) StartTime,
TIMEFROMPARTS(EndHour, EndMinute, EndSecond, 0, 0) EndTime
FROM T
) TT
GROUP BY [Date];
Returns:
+---------------------+--------+
| Date | MM:SS |
+---------------------+--------+
| 27/11/2018 00:00:00 | 15:30 |
| 30/11/2018 00:00:00 | 15:30 |
| 02/12/2018 00:00:00 | 107:10 |
+---------------------+--------+
Demo

Convert number of minutes to hh:mm

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

Rounding Datetime to nearest 15 minutes in SQL Server

I have a problem in SQL Server with rounding datetime. I got datetime in column rec_datetime, but I want to round this datetime in a new column r_datetime, which has to be rounded to nearest 15 min, for the whole column rec_datetime.
Example:
[2015-11-24 19:06:00.000] - expected result -> [2015-11-24 19:00:00.000]
[2015-11-24 19:09:00.000] - expected result -> [2015-11-24 19:15:00.000]
Is it possible to round it via select for whole column? Something like :
select round(rec_datetime.......
Round-down, round-nearest & round-up to nearest 15mins
DATEADD( minute, ( DATEDIFF( minute, 0, dateTimeX ) / 15 ) * 15, 0 ) AS dateTimeRoundDown
DATEADD( minute, ( DATEDIFF( minute, 0, DATEADD( second, ( 15 * 60 ) / 2, dateTimeX ) ) / 15 ) * 15, 0 ) AS dateTimeRoundNearest
DATEADD( minute, ( DATEDIFF( minute, 0, DATEADD( minute, 15 , dateTimeX ) ) / 15 ) * 15, 0 ) AS dateTimeRoundUp
Round Down
DATEADD( minute, ( DATEDIFF( minute, 0, dateTimeX ) / 15 ) * 15, 0 ) AS dateTimeRoundDown
Get the offset in minutes (number of minutes since the base-date):
DATEDIFF( minute, 0, dateTimeX )
Round-down to 15 minute block by integer dividing:
DATEDIFF( minute, 0, dateTimeX ) / 15 ) * 15
Add the base-date back in minutes:
DATEADD( minute, ( DATEDIFF( minute, 0, dateTimeX ) / 15 ) * 15, 0 )
Round Nearest
DATEADD( minute, ( DATEDIFF( minute, 0, DATEADD( second, ( 15 * 60 ) / 2, dateTimeX ) ) / 15 ) * 15, 0 ) AS dateTimeRoundNear
15 / 2 minutes is added to the offset.
Needs to be in seconds due to the integer division.
Round Up
DATEADD( minute, ( DATEDIFF( minute, 0, DATEADD( minute, 15, dateTimeX ) ) / 15 ) * 15, 0 ) AS dateTimeRoundUp
15 minutes is added to the offset
Base Date
I generally use a base date of 0 which is the SQL Server 'epoch'
SELECT DATEADD( minute, 0, 0 ) -- '1900-01-01 00:00:00.000'
Because DATEADD() & DATEDIFF() use the SQL Server data type of INT (32 bits) for the parameters, for dates in the very far future, this may cause an overflow.
Using another fixed date, eg '2010-01-01', will avoid the overflow.
The chosen base-date must have a time part of 00:00:00
Using a base-date and integer division, no casting & no floating point operations are required.
Unit Testing
DECLARE #start DATETIME = '2017-04-20 21:00:00'
DECLARE #end DATETIME = '2017-04-20 22:00:00'
;WITH CTE_dateTimes AS
(
SELECT #start AS dateTimeX
UNION ALL
SELECT DATEADD( minute, 1, dateTimeX )
FROM CTE_dateTimes
WHERE DATEADD( minute, 1, dateTimeX ) <= #end
)
SELECT dateTimeX,
DATEADD( minute, ( DATEDIFF( minute, 0, dateTimeX ) / 15 ) * 15, 0 ) AS dateTimeRoundDown,
DATEADD( minute, ( DATEDIFF( minute, 0, DATEADD( second, ( 15 * 60 ) / 2, dateTimeX ) ) / 15 ) * 15, 0 ) AS dateTimeRoundNearest,
DATEADD( minute, ( DATEDIFF( minute, 0, DATEADD( minute, 15 , dateTimeX ) ) / 15 ) * 15, 0 ) AS dateTimeRoundUp
FROM CTE_dateTimes
Try something like this:
SELECT
dateadd(minute, datediff(minute, '1999-12-31 23:52:30', col) / 15*15, '2000-01-01')
FROM (values('2015-11-24 19:06:00.000'),('2015-11-24 19:09:00.000')) x(col)
Result:
2015-11-24 19:00:00.000
2015-11-24 19:15:00.000
In this case you need to round the minute to nearest 15
try query like this:
SELECT
original_datetime
--: this will give you the minute part
, datepart(minute, original_datetime) AS minuteFromDate
--: now get the nearest minute part to 15min, round it nearest to 15
, round(datepart(minute, original_datetime) * 1.0 / 15 , 0) * 15.0 AS roundedToNearest15
-- now remove the minute from original datetime, & add the rounded minute to the resultant datetime value
-- this will give you expected result
, dateadd(minute
, (round(datepart(minute, original_datetime) * 1.0 / 15 , 0) * 15.0)
, dateadd(minute, -datepart(minute, original_datetime), original_datetime)
) as rec_datetime
FROM (values('2015-11-24 19:06:00.000')
,('2015-11-24 19:09:00.000')
,('2015-11-24 19:56:00.000')
,('2015-11-24 19:48:00.000')
) x(original_datetime)
Nearest 15 minutes:
SELECT DateTimeX = GETDATE(), RoundedDateTimeX = CAST(CAST(CAST(GETDATE() as float) * (24 * 60/15) + 0.5 as bigint) / (24.0 * 60/15) as datetime)
Nearest 15 minutes rounded up:
SELECT DateTimeX = GETDATE(), RoundedDateTimeX = CAST(CAST(CAST(GETDATE() as float) * (24 * 60/15) + 1 as bigint) / (24.0 * 60/15) as datetime)
Note: The decimal 24.0 in devisor changes type back to float.

grouping in sql server with for xml

I have a table in the following format
reporting_date interest_payment balance
200401 10 10
200402 20 15
200403 30 20
200404 40 30
200405 50 40
200406 60 50
200407 70 60
i wanted to generate an OUTPUT in the following format :
The output of the query should look like this :
reporting_date interest_payment balance
Q1 -2004 60 10
Q2 -2004 150 30
Q3 -2004 70 60
Q4 -2004 0 0
i.e i wanted to represent data by quarter and year and group by quarter and year for interest_payment column but for balance i need to pick up the value from the first reporting date in that quarter ,so as you can see q1-2004 has 10,15 and 20 but only 10 is accounted as that was the first reporting date in that quarter
I have my query working for interest payment but i am not sure how do i pickup the first reporting value for balance in a quarter
SELECT report_year as "#date",'Q'+CAST(report_quarter+1 as varchar(1)) as "#quarter", SUM(a.balance) as "#balance", SUM(a.interest_payment) as "#interest_payment"
FROM (SELECT *,
(reporting_date%100 - 1)/3 as report_quarter,
reporting_date/100 as report_year
FROM employee) a
GROUP by report_year, report_quarter
order by report_year, report_quarter
First, create all combination of years and quarters. Then use window functions such AS SUM OVER() and ROW_NUMBER() for the interest_payment and balance.
CREATE TABLE #temp(
reporting_date INT,
interest_payment INT,
balance INT
)
INSERT INTO #temp VALUES
(200401, 10, 10), (200402, 20, 15), (200403, 30, 20),
(200404, 40, 30), (200405, 50, 40), (200406, 60, 50),
(200407, 70, 60);
;WITH quarters(yr, qtr) AS(
SELECT
y.N, q.N
FROM(
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
) q(N)
CROSS JOIN(
SELECT DISTINCT reporting_date / 100 FROM #temp
) y(N)
)
,GroupedByQtr AS(
SELECT
*,
qtr = (reporting_date % 100 -1) / 3 + 1,
yr = reporting_date / 100,
ss = SUM(interest_payment) OVER(PARTITION BY (reporting_date / 100), ((reporting_date % 100 -1) / 3 + 1)),
rn = ROW_NUMBER() OVER(PARTITION BY (reporting_date / 100), ((reporting_date % 100 -1) / 3 + 1) ORDER BY reporting_date)
FROM #temp
)
SELECT
reporting_date = 'Q' + CONVERT(VARCHAR(1), q.qtr) + ' - ' + CONVERT(VARCHAR(4), q.yr),
interest_payment = ISNULL(g.ss, 0),
balance = ISNULL(g.balance, 0)
FROM quarters q
LEFT JOIN GroupedByQtr g
ON g.qtr = q.qtr
AND g.yr = q.yr
AND g.rn = 1
RESULT
reporting_date interest_payment balance
-------------- ---------------- -----------
Q1 - 2004 60 10
Q2 - 2004 150 30
Q3 - 2004 70 60
Q4 - 2004 0 0

Resources