I'm looking for a function where i can define working hours eg 9am - 5 pm and then add working hours to a datetime eg datetime 2021-08-05 16:30:00 add 3 working hours so the date time would be 2021-08-06 11:30:00.
I currently do this with working days see code below
This is to calculate SLA on a task eg task comes in at 2021-08-05 16:30:00 SLA is 3 working hours so it needs to be completed by 2021-08-06 11:30:00.
Any help would be appreciated
Thanks
declare
#ReturnDate datetime,
#StartDate datetime,
#CountDays int,
#Country varchar (255)
set #StartDate = '2021-08-05 16:30:00.000'
set #CountDays = 2
set #Country = 'England and Wales'
;with cteWorkingDates as
(
select DAT.Calendar_Date_Date,
ROW_NUMBER () over (
order by DAT.Calendar_Date_Date
) as RowNo
from dwBoyce.archway.Calendar_Date DAT with (nolock)
left join dwBoyce.archway.GovUK_BankHolidays BAH with (nolock) on DAT.Calendar_Date_Date = BAH.GovUK_BankHolidays_Date
and #Country = BAH.GovUK_BankHolidays_Country
where DAT.Calendar_Date_Date > #StartDate
and DAT.Calendar_Date_WorkingDay = 1
and BAH.GovUK_BankHolidays_Date is null
)
select cast(wd.Calendar_Date_Date as datetime) + DATEADD(day, 0 - DATEDIFF(day, 0, #StartDate), #StartDate)
from cteWorkingDates WD
where WD.RowNo = #CountDays
You might want to try the following:
Evaluate, how many minutes of working time are remaining starting from the time the ticket has been created. Then calculate the number of minutes the SLA request may take (in your case 3 * 60 = 180 minutes). When the remaining working time is less than the SLA time in minutes, the answer time will be Ticket time + 1 day + (SLA minutes - remaining working time in minutes).
Following an example:
DECLARE #WorkingHoursStart TIME = '09:00:00.000';
DECLARE #WorkingHoursEnd TIME = '17:00:00.000';
DECLARE #WorkingHoursCount INT = DATEDIFF(HOUR, #WorkingHoursStart, #WorkingHoursEnd);
DECLARE #SLAHours INT = 32;
DECLARE #TicketTimestamp DATETIME = '2022-11-01 12:30:00';
DECLARE #TicketWorkingHoursStart DATETIME = DATETIMEFROMPARTS(YEAR(#TicketTimestamp)
,MONTH(#TicketTimestamp)
,DAY(#TicketTimestamp)
,DATEPART(HOUR, #WorkingHoursStart)
,DATEPART(MINUTE, #WorkingHoursStart)
,0
,0);
DECLARE #TicketWorkingHoursEnd DATETIME = DATETIMEFROMPARTS(YEAR(#TicketTimestamp)
,MONTH(#TicketTimestamp)
,DAY(#TicketTimestamp)
,DATEPART(HOUR, #WorkingHoursEnd)
,DATEPART(MINUTE, #WorkingHoursEnd)
,0
,0);
DECLARE #TicketWorkingTimestamp DATETIME = CASE
WHEN #TicketTimestamp < #TicketWorkingHoursStart
THEN #TicketWorkingHoursStart
WHEN #TicketTimestamp > #TicketWorkingHoursEnd
THEN DATEADD(d, 1, #TicketWorkingHoursStart)
ELSE #TicketTimestamp
END;
DECLARE #TmpTimeStamp DATETIME = DATEADD(d, #SLAHours/#WorkingHoursCount, #TicketWorkingTimestamp);
DECLARE #TmpSLAHours INT = #SLAHours - ((#SLAHours/#WorkingHoursCount)*#WorkingHoursCount);
DECLARE #TmpSLAMinutes INT = #TmpSLAHours * 60;
DECLARE #AnswerTimestamp DATETIME = CASE
WHEN DATEDIFF(MINUTE, CAST(#TmpTimeStamp AS TIME), #WorkingHoursEnd) < #TmpSLAMinutes
THEN DATEADD(MINUTE
,#TmpSLAMinutes - DATEDIFF(MINUTE
,CAST(#TmpTimeStamp AS TIME)
,#WorkingHoursEnd)
,DATEADD(DAY
,CASE WHEN #TmpSLAHours/#WorkingHoursCount = 0 THEN 1 ELSE 0 END
,DATETIMEFROMPARTS(YEAR(#TmpTimeStamp)
,MONTH(#TmpTimeStamp)
,DAY(#TmpTimeStamp)
,DATEPART(HOUR, #WorkingHoursStart)
,DATEPART(MINUTE, #WorkingHoursStart)
,DATEPART(SECOND, #TmpTimeStamp)
,0)
)
)
ELSE DATEADD(MINUTE, #TmpSLAMinutes, #TmpTimeStamp)
END
DECLARE #WeekEndDaySkip INT = ((DATEPART(WEEKDAY, #TicketTimestamp)+DATEDIFF(d, #TicketTimestamp, #AnswerTimestamp))/7)*2
SELECT #TicketTimestamp AS TicketTime
, #AnswerTimestamp AS AnswerTimestamp
, DATEADD(d, #WeekEndDaySkip, #AnswerTimestamp) AS AnswerTimestampWOWeekend
Adding this deals with SLAs that span over weekends
declare
#date1 date = cast(#TicketTimestamp as date)
,#date2 date = cast(#TmpTimeStamp as date)
declare #Count int
Select #Count = count(*)
from archway.Calendar_Date d
where d.Calendar_Date_Date between #date1 and #date2
and Calendar_Date_DayName in ('Saturday','Sunday')
DECLARE #TmpTimeStamp1 DATETIME = case when #count = 2 then DATEADD(d,#count,#TmpTimeStamp)
else #TmpTimeStamp end
Related
I need to change a passed variable date if the date falls under the current year Nov 1st to Dec 31st
How to do this in TSQL?
Example:
Example #1
#ip_batch_date = '2020-12-01T00:00:00'
check #ip_batch_date >=' '2020-11-01T00:00:00' AND #ip_batch_date<='2020-12-31T00:00:00'
Then #ip_batch_date = '2021-01-01T00:00:00'
Example #2
#ip_batch_date = '2021-11-15T00:00:00'
check #ip_batch_date >='2021-11-01T00:00:00' AND #ip_batch_date<='2021-12-31T00:00:00'
Then #ip_batch_date = '2022-01-01T00:00:00'
Assuming you already have a passed in date variable called #ip_batch_date, off the top of my head I would use something like
IF (YEAR(#ip_batch_date) = YEAR(GetDate()) AND MONTH(#ip_batch_date) BETWEEN 11 AND 12)
SET #ip_batch_date = DATEFROMPARTS(YEAR(GetDate())+1,1,1);
If instead of a passed in date, you were writing a query that was going to process lots of rows with a date column in them that you wanted to subject this logic to, it would be best not to have ip_date_column converted by a function, but rather to leave the date column bare and compare it to two constructed dates, like this:
CASE WHEN my_date_column BETWEEN DATEFROMPARTS(YEAR(GetDate()),11,1)
DATEFROMPARTS(YEAR(GetDate()),12,31)
THEN DATEFROMPARTS(YEAR(GetDate())+1,1,1);
ELSE my_date_column
END
Finally, if my_date_column was a datetime or datetime2 column instead of just a date, make sure you you datetimefromparts or datetime2fromparts instead, and add the time in as well to avoid last day boundary issues
If I understood your question correctly:
DECLARE #Date DATETIME
SET #Date = '2020-12-01T00:00:00'
SET #Date = CASE WHEN RIGHT(CONVERT(VARCHAR(8), #Date, 112), 4) >= 1101 THEN DATEADD(yy, DATEDIFF(yy, 0, #Date) + 1, 0) ELSE #Date END
SELECT #Date
-- Output : 2021-01-01 00:00:00.000
SET #Date = '2021-12-01T00:00:00'
SET #Date = CASE WHEN RIGHT(CONVERT(VARCHAR(8), #Date, 112), 4) >= 1101 THEN DATEADD(yy, DATEDIFF(yy, 0, #Date) + 1, 0) ELSE #Date END
SELECT #Date
-- Output : 2022-01-01 00:00:00.000
DECLARE #IP_BATCH_DATE DATETIME= '2020-12-01T00:00:00'
IF #ip_batch_date >= '2020-11-01T00:00:00' AND #ip_batch_date<='2020-12-31T00:00:00'
BEGIN
SELECT datefromparts(YEAR(GETDATE()), 1, 1)
END
ELSE
BEGIN
SELECT #ip_batch_date
END
This question may be duplicate sorry for it,As I could not able to find any solution in web till now so am Posting this
I need to create a SQL server functions where I need to replace only the date part from the actual date ..
For example if the actual date is 01/10/2016 means I need to update the actual date to 15/10/2016 the date part alone is replaced from 01 to 15 I need to achieve this, please help me in solving this as am very new to SQL SERVER
DECLARE #actual_due_date INT = 5;
DECLARE #invoice_date DATETIME = '20161210';
DECLARE #due_date DATETIME;
SET #due_date=DATEADD(DAY,#actual_due_date-DATEPART(DAY,#invoice_date),#invoice_date);
SELECT #due_date;
This prints out
2016-12-05 00:00:00.000
Here's another way to do it:
DECLARE #oldDate DATETIME = '2016-10-17 10:29:22'
DECLARE #replacingDate DATE = '2016-10-15'
DECLARE #newDate DATETIME
SET #newDate = CONVERT(datetime, CONVERT(varchar, #replacingDate)+' '+ LEFT(CONVERT(varchar, CONVERT(time, #oldDate)), 8))
SELECT #newDate
--UPDATE TableA
--SET FieldX = CONVERT(datetime, CONVERT(varchar, #replacingDate)+' '+ LEFT(CONVERT(varchar, CONVERT(time, #oldDate)), 8))
--WHERE SomeCondition
Don't know, what you really try to achieve, but you could try this:
DECLARE #OtherDate DATETIME = {ts'2016-02-05 12:00:00'}; --Some day in February, 12 o'clock
DECLARE #actualDate DATETIME = GETDATE(); --current day and time
--This comes back with the other date, but the actual time
SELECT CAST(CAST(#OtherDate AS date) AS datetime) + CAST(CAST(#actualDate AS time) AS datetime);
Not sure of the purpose, why you are replacing it.
Here is one way:
Declare #date date = '01/10/2016'
Select Replace(Convert(varchar(20), #date, 101), '01/', '15/') AS ReplacedDate
-- 15/10/2016
I have a select query that has DURATION column to calculate number of Minutes . I want to convert those minutes to hh:mm format.
Duration has values like 60, 120,150
For example:
60 becomes 01:00 hours
120 becomes 02:00 hours
150 becomes 02:30 hours
Also, this is how I retrieve DURATION (Minutes)
DATEDIFF(minute, FirstDate,LastDate) as 'Duration (Minutes)'
You can convert the duration to a date and then format it:
DECLARE
#FirstDate datetime,
#LastDate datetime
SELECT
#FirstDate = '2000-01-01 09:00:00',
#LastDate = '2000-01-01 11:30:00'
SELECT CONVERT(varchar(12),
DATEADD(minute, DATEDIFF(minute, #FirstDate, #LastDate), 0), 114)
/* Results: 02:30:00:000 */
For less precision, modify the size of the varchar:
SELECT CONVERT(varchar(5),
DATEADD(minute, DATEDIFF(minute, #FirstDate, #LastDate), 0), 114)
/* Results: 02:30 */
This function is to convert duration in minutes to readable hours and minutes format. i.e 2h30m. It eliminates the hours if the duration is less than one hour, and shows only the hours if the duration in hours with no extra minutes.
CREATE FUNCTION [dbo].[MinutesToDuration]
(
#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)) + 'h' +
CASE WHEN (#minutes % 60) > 0 THEN
CAST((#minutes % 60) AS VARCHAR(2)) + 'm'
ELSE
''
END)
ELSE
CAST((#minutes % 60) AS VARCHAR(2)) + 'm'
END
return #hours
END
To use this function :
SELECT dbo.MinutesToDuration(23)
Results: 23m
SELECT dbo.MinutesToDuration(120)
Results: 2h
SELECT dbo.MinutesToDuration(147)
Results: 2h27m
Hope this helps!
I'm not sure these are the best options but they'll definitely get the job done:
declare #durations table
(
Duration int
)
Insert into #durations(Duration)
values(60),(80),(90),(150),(180),(1000)
--Option 1 - Manually concatenate the values together
select right('0' + convert(varchar,Duration / 60),2) + ':' + right('0' + convert(varchar,Duration % 60),2)
from #Durations
--Option 2 - Make use of the time variable available since SQL Server 2008
select left(convert(time,DATEADD(minute,Duration,0)),5)
from #durations
GO
DECLARE #Duration int
SET #Duration= 12540 /* for example big hour amount in minutes -> 209h */
SELECT CAST( CAST((#Duration) AS int) / 60 AS varchar) + ':' + right('0' + CAST(CAST((#Duration) AS int) % 60 AS varchar(2)),2)
/* you will get hours and minutes divided by : */
For those who need convert minutes to time with more than 24h format:
DECLARE #minutes int = 7830
SELECT CAST(#minutes / 60 AS VARCHAR(8)) + ':' + FORMAT(#minutes % 60, 'D2') AS [Time]
Result:
130:30
This seems to work for me:
SELECT FORMAT(#mins / 60 * 100 + #mins % 60, '#:0#')
Thanks to A Ghazal, just what I needed. Here's a slightly cleaned up version of his(her) answer:
create FUNCTION [dbo].[fnMinutesToDuration]
(
#minutes int
)
RETURNS nvarchar(30)
-- Based on http://stackoverflow.com/questions/17733616/how-to-convert-number-of-minutes-to-hhmm-format-in-tsql
AS
BEGIN
return rtrim(isnull(cast(nullif((#minutes / 60)
, 0
) as varchar
) + 'h '
,''
)
+ isnull(CAST(nullif((#minutes % 60)
,0
) AS VARCHAR(2)
) + 'm'
,''
)
)
end
select convert(varchar(5),dateadd(mi,DATEDIFF(minute, FirstDate,LastDate),'00:00'),114)
In case someone is interested in getting results as
60 becomes 01:00 hours, 120 becomes 02:00 hours, 150 becomes 02:30 hours, this function might help:
create FUNCTION [dbo].[MinutesToHHMM]
(
#minutes int
)
RETURNS varchar(30)
AS
BEGIN
declare #h int
set #h= #minutes / 60
declare #mins varchar(2)
set #mins= iif(#minutes%60<10,concat('0',cast((#minutes % 60) as varchar(2))),cast((#minutes % 60) as varchar(2)))
return iif(#h <10, concat('0', cast(#h as varchar(5)),':',#mins)
,concat(cast(#h as varchar(5)),':',#mins))
end
I would do the following (copy-paste the whole stuff below into immediate window / query window and execute)
DECLARE #foo int
DECLARE #unclefoo smalldatetime
SET #foo = DATEDIFF(minute, CAST('2013.01.01 00:00:00' AS datetime),CAST('2013.01.01 00:03:59' AS datetime)) -- AS 'Duration (Minutes)'
SET #unclefoo = DATEADD(minute, #foo, '2000.01.01')
SELECT CAST(#unclefoo AS time)
#foo stores the value you generate in your question. The "trick" comes by then:
we create a smalldatetime variable (in my case it's yyyy.mm.dd format) and increment it with your int value, then display (or store if you want) the time part only.
declare function dbo.minutes2hours (
#minutes int
)
RETURNS varchar(10)
as
begin
return format(dateadd(minute,#minutes,'00:00:00'), N'HH\:mm','FR-fr')
end
How to get the First and Last Record time different in sql server....
....
Select EmployeeId,EmployeeName,AttendenceDate,MIN(Intime) as Intime ,MAX(OutTime) as OutTime,
DATEDIFF(MINUTE, MIN(Intime), MAX(OutTime)) as TotalWorkingHours
FROM ViewAttendenceReport WHERE AttendenceDate >='1/20/2020 12:00:00 AM' AND AttendenceDate <='1/20/2020 23:59:59 PM'
GROUP BY EmployeeId,EmployeeName,AttendenceDate;
If you want a notation of XX days YY hours and ZZ min, just try:
SELECT
CAST(f.TimeAmount / 1440 AS VARCHAR(8)) + 'd ' +
CAST((f.TimeAmount % 1440) / 60 AS VARCHAR(8)) + 'h ' +
FORMAT(f.TimeAmount % 60, 'D2') + 'min' AS [TIME_TEXT]
FROM
MyTable f
I need to calculate difference in workdays between two dates. Is there a built in function for this in SQL Server? Can someone please provide an example on how to do this?
Here is something I wrote quickly. Just encapsulate it into a function or whatever you need.
declare #StartDate datetime
declare #EndDate datetime
declare #TotalDiff int
declare #NumberOfWeekends int
SET #StartDate = '3/12/2013'
SET #EndDate = '3/22/2013'
SET #NumberOfWeekends = 0
SET #TotalDiff = DATEDIFF(d,#StartDate, #EndDate)
If #TotalDiff > 7
SET #NumberOfWeekends = #TotalDiff / 7
else if DATEPART(dd, #EndDate) < DATEPART(DD, #StartDate)
SET #NumberOfWeekends = 1
select (#TotalDiff - 2*#NumberOfWeekends) as TotalWorkDays
No, there is nothing built in to SQL Server to directly give you number of working days between two dates, however there are a few built-in functions which will enable you to write one.
Firstly, a few caveats
The world cannot agree what a "Working Day" is. For most of us it's Saturday and Sunday. For most of the Middle East it's Friday & Saturday (with Sunday being a normal working day)
The world most certainly cannot agree on what constitutes a public holiday, which are almost always considered non-working days.
You have not specified how you would like to handle these cases so lets make some assumptions:
Saturday and Sunday will be non-working days
Public holidays will not be taken into acount
Now, determining if a particular days is saturday or sunday in sql is easy, given a #date of type DateTime:
IF DATENAME(dw,#date) IN ('Saturday','Sunday')
With that in mind, given a start and end date, you can just count incrementally from #startDate to #endDate
DECLARE #startDate DATETIME = '2013-01-01'
DECLARE #endDate DATETIME = '2013-01-20'
DECLARE #currDate DATETIME = #startDate
DECLARE #numDays INT = 0
WHILE #currDate<#endDate
BEGIN
IF DATENAME(dw,#currDate) NOT IN ('Saturday','Sunday')
SET #numDays = #numDays + 1
SET #currDate = DATEADD(day,1,#currDate)
END
SELECT #numDays
Note: This is non-inclsive so wont count #endDate. You could change it to be inclusive by changing WHILE #currDate<#endDate to WHILE #currDate<=#endDate
My solution does not count the #EndDate, so if you need to change that, just add 1 to #d2.
First, I calculate the number of days from an "initial" day (which happens to be 1/1/1900, a Monday) to #StartDate and #EndDate:
DECLARE #d1 int = DATEDIFF(Day, 0, #StartDate);
DECLARE #d2 int = DATEDIFF(Day, 0, #EndDate);
Then, the total number of days between #StartDate and #EndDate is:
#d2 - #d1
From this, I substract the number of Sundays and the number of Saturdays in the interval, each calculated as a difference simlar to the total days, but now for whole weeks (7 days). To get the number of whole weeks, I use integer division by 7 and the fact that the "initial" day (0) is a Monday. The number of Sundays in the interval is
#d2/7 - #d1/7
and the number of Saturdays is
(#d2+1)/7 - (#d1+1)/7
Putting all together, my solution is:
DECLARE #StartDate DATETIME = '20180101'
DECLARE #EndDate DATETIME = '20180201'
DECLARE #d1 int = DATEDIFF(Day, 0, #StartDate)
DECLARE #d2 int = DATEDIFF(Day, 0, #EndDate)
SELECT #d2 - #d1 - (#d2/7 - #d1/7) - ((#d2+1)/7 - (#d1+1)/7) AS workdays
How to subtract two time values in SQL Server 2008. I am using time variables in a stored procedure.
Please help.
You can use DATEDIFF():
SELECT DATEDIFF(Day, startDate, endDate)
FROM table
SELECT DATEDIFF(Second, date, GETDATE())
FROM table
DECLARE #END TIME = '16:00:00.0000000' ,
#START TIME = '01:00:00.0000000'
SELECT convert(TIME,dateadd(ms,DateDiff(ss, #START, #END )*1000,0),114)
following expression works for me
declare #starttime Time, #endtime Time
set #starttime='18:45'
set #endtime='22:45'
select DATEDIFF(HH,#starttime, #endtime)
output: 4
Even You are using offset value or normal dates this code will give you appropriate answers.
BEGIN TRY
DECLARE #OffSetVal1 VARCHAR(39) = '2019-12-02 09:15:29 +14:00'
, #OffSetVal2 VARCHAR(39) = '2019-12-02 09:15:29 +12:30'
, #minutes INT = 0
, #OffSetDiff VARCHAR(19) = ''
, #HourDiff INT = 0
SET #HourDiff = DATEDIFF(HOUR,#OffSetVal1,#OffSetVal2) -- To Check digits of hours.
SET #minutes = DATEDIFF(MINUTE,#OffSetVal1,#OffSetVal2) -- To Convert minutes to hours.
SET #OffSetDiff = #minutes / 60 + (#minutes % 60) / 100.0 -- To Check '+' Or '-' And To Get Value.
SELECT CASE WHEN CAST(#OffSetDiff AS FLOAT) <= 0
THEN (CASE WHEN #HourDiff < 10
THEN FORMAT(CAST(#OffSetDiff AS FLOAT),'0#.00')
ELSE FORMAT(CAST(#OffSetDiff AS FLOAT),'0#.00')
END)
ELSE (CASE WHEN #HourDiff < 10
THEN '+'+FORMAT(CAST(#OffSetDiff AS FLOAT),'0#.00')
ELSE '+'+FORMAT(CAST(#OffSetDiff AS FLOAT),'0#.00')
END)
END
END TRY
BEGIN CATCH
PRINT N'It seems you provided an invalid DateTimeOffSet Parameter. '
END CATCH
ANS :- +01.30 (# The offset differences with hour and minute and if you don't want that '+' simply remove from code & then run the code)