简体   繁体   English

使用营业时间和假期计算截止日期

[英]Calculating due date using business hours and holidays

I need to calculate due date / end date for SLAs.我需要计算 SLA 的截止日期/结束日期。 As input values I have the start date and a timespan (in minutes).作为输入值,我有开始日期和时间跨度(以分钟为单位)。 This calculation needs to take into account business hours, weekends, and holidays.此计算需要考虑营业时间、周末和节假日。

I've seen a lot of examples where the input is start date and end date, but have been struggling finding anything similar to the above input values.我看过很多例子,其中输入是开始日期和结束日期,但一直在努力寻找与上述输入值类似的东西。

Is there an elegant solution to this problem?这个问题有优雅的解决方案吗? Is there a way to calculate due date without using a loop?有没有一种方法可以在不使用循环的情况下计算截止日期? I can't think of a way to do the calculation without doing something similar to the following terrible algorithm:如果不做类似于以下可怕算法的事情,我想不出一种方法来进行计算:

  1. Create a return variable "due date" and set it to input variable "start date"创建返回变量“截止日期”并将其设置为输入变量“开始日期”
  2. Create a control variable "used minutes" and set it to 0创建一个控制变量“used minutes”并将其设置为0
  3. Create a loop with the condition "used minutes" <= "input timespan"使用条件“使用分钟”<=“输入时间跨度”创建一个循环
  4. Inside the loop, add a second to the "due date" return variable在循环内,向“截止日期”返回变量添加一秒
  5. Inside the loop, check if the second is within hours of operation (checking business hours, weekends, and holidays).在循环内部,检查第二个是否在营业时间(检查营业时间、周末和节假日)内。 If so, increment control variable "used minutes" by 1.如果是这样,将控制变量“使用的分钟数”增加 1。
  6. Upon exiting the loop, return variable "due date"退出循环后,返回变量“截止日期”

You need a table with valid business hours, with the weekends and holidays excluded (or marked as weekend/holiday so you can skip them.) Each row represents one day and the number of working hours for that day.您需要一个包含有效营业时间的表格,其中不包括周末和节假日(或标记为周末/节假日,以便您可以跳过它们。)每一行代表一天和当天的工作小时数。 Then you query the business hours table from your start date to the first (min) date where the sum(hours*60) is greater than your minutes parameter, excluding marked weekend/holiday rows.然后您查询营业时间表,从您的开始日期到第一个(分钟)日期,其中总和(小时 * 60)大于您的分钟参数,不包括标记的周末/假日行。 That gives you your end date.这为您提供了结束日期。

Here's the day table:这是日表:

CREATE TABLE [dbo].[tblDay](
    [dt] [datetime] NOT NULL,
    [dayOfWk] [int] NULL,
    [dayOfWkInMo] [int] NULL,
    [isWeekend] [bit] NOT NULL,
    [holidayID] [int] NULL,
    [workingDayCount] [int] NULL,
 CONSTRAINT [PK_tblDay] PRIMARY KEY CLUSTERED 
(
    [dt] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

here's how I populate the table with days:这是我用天填充表格的方式:

CREATE PROCEDURE [dbo].[usp_tblDay]
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE  
        @Dt datetime ,
        @wkInMo int,
        @firstDwOfMo int,
        @holID int,
        @workDayCount int,
        @weekday int,
        @month int,
        @day int,
        @isWkEnd bit

    set @workDayCount = 0
    SET @Dt = CONVERT( datetime, '2008-01-01' ) 
    while @dt < '2020-01-01'
    begin
        delete from tblDay where dt = @dt

        set @weekday = datepart( weekday, @Dt )
        set @month = datepart(month,@dt)
        set @day = datepart(day,@dt)

        if @day = 1  -- 1st of mo
            begin
                set @wkInMo = 1
                set @firstDwOfMo = @weekday
            end

        if ((@weekday = 7) or (@weekday = 1)) 
            set @isWkEnd = 1 
        else 
            set @isWkEnd = 0

        if @isWkEnd = 0 and (@month = 1 and @day = 1) 
            set @holID=1        -- new years on workday
        else if @weekday= 6 and (@month = 12 and @day = 31) 
            set @holID=1        -- holiday on sat, change to fri
        else if @weekday= 2 and (@month = 1 and @day = 2) 
            set @holID=1        -- holiday on sun, change to mon

        else if @wkInMo = 3 and @weekday= 2 and @month = 1 
            set @holID = 2      -- mlk

        else if @wkInMo = 3 and @weekday= 2 and @month = 2 
            set @holID = 3      -- President’s

        else if @wkInMo = 4 and @weekday= 2 and @month = 5 and datepart(month,@dt+7) = 6
            set @holID = 4      -- memorial on 4th mon, no 5th
        else if @wkInMo = 5 and @weekday= 2 and @month = 5 
            set @holID = 4      -- memorial on 5th mon

        else if @isWkEnd = 0 and (@month = 7 and @day = 4) 
            set @holID=5        -- July 4 on workday
        else if @weekday= 6 and (@month = 7 and @day = 3) 
            set @holID=5        -- holiday on sat, change to fri
        else if @weekday= 2 and (@month = 7 and @day = 5) 
            set @holID=5        -- holiday on sun, change to mon

        else if @wkInMo = 1 and @weekday= 2 and @month = 9 
            set @holID = 6      -- Labor

        else if @isWkEnd = 0 and (@month = 11 and @day = 11) 
            set @holID=7        -- Vets day on workday
        else if @weekday= 6 and (@month = 11 and @day = 10) 
            set @holID=7        -- holiday on sat, change to fri
        else if @weekday= 2 and (@month = 11 and @day = 12) 
            set @holID=7        -- holiday on sun, change to mon

        else if @wkInMo = 4 and @weekday= 5 and @month = 11 
            set @holID = 8      -- thx

        else if @holID = 8
            set @holID = 9      -- dy after thx

        else if @isWkEnd = 0 and (@month = 12 and @day = 25) 
            set @holID=10       -- xmas day on workday
        else if @weekday= 6 and (@month = 12 and @day = 24) 
            set @holID=10       -- holiday on sat, change to fri
        else if @weekday= 2 and (@month = 12 and @day = 26) 
            set @holID=10       -- holiday on sun, change to mon
        else
            set @holID = null

        insert into tblDay select @dt,@weekday,@wkInMo,@isWkEnd,@holID,@workDayCount

        if @isWkEnd=0 and @holID is null 
            set @workDayCount = @workDayCount + 1

        set @dt = @dt + 1
        if datepart( weekday, @Dt ) = @firstDwOfMo 
            set @wkInMo = @wkInMo + 1
    end
END

I also have a holiday table, but everyone's holidays are different:我也有一个假期表,但是每个人的假期都不一样:

holidayID   holiday rule description
1   New Year's Day  Jan. 1
2   Martin Luther King Day  third Mon. in Jan.
3   Presidents' Day third Mon. in Feb.
4   Memorial Day    last Mon. in May
5   Independence Day    4-Jul
6   Labor Day   first Mon. in Sept
7   Veterans' Day   Nov. 11
8   Thanksgiving    fourth Thurs. in Nov.
9   Fri after Thanksgiving  Friday after Thanksgiving
10  Christmas Day   Dec. 25

HTH HTH

This is the best I could do, still uses a loop but uses date functions instead of incrementing a minutes variable.这是我能做的最好的事情,仍然使用循环但使用日期函数而不是增加分钟变量。 Hope you like it.希望你喜欢。


--set up our source data
declare @business_hours table
(
    work_day    varchar(10),
    open_time   varchar(8), 
    close_time  varchar(8)
)
insert into @business_hours values ('Monday',   '08:30:00', '17:00:00')
insert into @business_hours values ('Tuesday',  '08:30:00', '17:00:00')
insert into @business_hours values ('Wednesday', '08:30:00', '17:00:00')
insert into @business_hours values ('Thursday', '08:30:00', '17:00:00')
insert into @business_hours values ('Friday',   '08:30:00', '18:00:00')
insert into @business_hours values ('Saturday', '09:00:00', '14:00:00')

declare @holidays table ( holiday varchar(10) ) insert into @holidays values ('2015-01-01') insert into @holidays values ('2015-01-02')

--Im going to assume the SLA of 2 standard business days (0900-1700) = 8*60*2 = 960 declare @start_date datetime = '2014-12-31 16:12:47' declare @time_span int = 960-- time till due in minutes

declare @true bit = 'true' declare @false bit = 'false'

declare @due_date datetime --our output

--other variables declare @date_string varchar(10) declare @today_closing datetime declare @is_workday bit = @true declare @is_holiday bit = @false

--Given our timespan is in minutes, lets also assume we dont care about seconds in start or due dates set @start_date = DATEADD(ss,datepart(ss,@start_date)*-1,@start_date)

while (@time_span > 0) begin

set @due_date       = DATEADD(MINUTE,@time_span,@start_date)
set @date_string    = FORMAT(DATEADD(dd, 0, DATEDIFF(dd, 0, @start_date)),'yyyy-MM-dd')
set @today_closing  = (select convert(datetime,@date_string + ' ' + close_time) from @business_hours where work_day = DATENAME(weekday,@start_date))

if exists((select work_day from @business_hours where work_day = DATENAME(weekday,@start_date))) 
    set @is_workday = @true 
else 
    set @is_workday = @false

if exists(select holiday from @holidays where holiday = @date_string)
    set @is_holiday = @true
else 
    set @is_holiday = @false

if  @is_workday = @true and @is_holiday = @false
begin
    if @due_date > @today_closing 
        set @time_span = @time_span - datediff(MINUTE, @start_date, @today_closing)
    else 
        set @time_span = @time_span - datediff(minute, @start_date, @due_date)
end

set @date_string = FORMAT(DATEADD(dd, 1, DATEDIFF(dd, 0, @start_date)),'yyyy-MM-dd')
set @start_date = CONVERT(datetime, @date_string + ' ' + isnull((select open_time from @business_hours where work_day = DATENAME(weekday,convert(datetime,@date_string))),''))

end

select @due_date

Sql to Calculate due date excluding holidays and considering business hour as below :- < note : - It's working correctly Business hour (8-5) Maintain holiday table Sql计算不包括假期的截止日期并考虑营业时间如下:- <注意:-工作正常营业时间(8-5)维护假期表

CREATE TABLE [dbo].[holiday](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [region] [nvarchar](10) NULL,
    [Hdate] [date] NULL,
)

> >

declare @start datetime= getdate()
declare @slamins int =960 --- SLA time in mins
declare @Country varchar(2)='NA'
declare @start_hour int = 8 -- business start hour
declare @end_hour int = 17 -- business end hour
declare @true bit = 'true'
declare @false bit = 'false'
declare @is_workday bit = @true
declare @is_holiday bit = @false
declare @due_date datetime
declare @today_closing datetime
declare @temp int = 0
declare  @holidays table (HDate DateTime)   --  Table variable to hold holidayes

---- Get country holidays from table based on the country code (Feel free to remove this or modify as per your DB schema)
 Insert Into @Holidays (HDate) Select date from HOLIDAY Where region=@Country and Hdate>=DateAdd(dd, DateDiff(dd,0,@start), 0)

--check for weekends
set @start =  case(datepart(dw,@start)+@@datefirst-1)%7 
      when 0 then Convert(dateTime,CONVERT(varchar,@start+1,101)+' 08:00:00')
      when 6 then Convert(dateTime,CONVERT(varchar,@start+2,101)+' 08:00:00')
      else @start end 

-- check if start time is before business hour
if datepart(hh, @start) < @start_hour set @start = Convert(dateTime,CONVERT(varchar,@start,101)+' 08:00:00')

-- check if start time is after business hour
if datepart(hh, @start) >= @end_hour set @start = Convert(dateTime,CONVERT(varchar,@start+1,101)+' 08:00:00')

-- loop start
while (@slamins > 0)
begin
 -- prepared closing date time based on start date
 set @today_closing = Convert(dateTime,CONVERT(varchar,@start,101)+' 17:00:00')
 set @due_date      = @start
 -- calculate number of Minute between start date and closing date
 set @temp = DATEDIFF(N, @start , @today_closing);

 --check for weekends
if (DATEPART(dw, @start)!=1 AND DATEPART(dw, @start)!=7) 
    set @is_workday = @true 
else 
    set @is_workday = @false
--check for holidays
if (Select Count(*) From @Holidays Where HDATE=DateAdd(dd, DateDiff(dd,0,@start), 0)) = 0
    set @is_holiday =@false 
else 
    set @is_holiday = @true
if  @is_workday = @true and @is_holiday = @false
begin

    if(@temp  <  @slamins)
    begin
        set @slamins = @slamins - @temp
    end
else 
    begin
        set @due_date = DATEADD(MINUTE,@slamins,@start)
        set @slamins = 0
        print @due_date
    end
end
set @start = Convert(dateTime,CONVERT(varchar,@start+1,101)+' 08:00:00')
end

select @due_date

Here is an option using a WorkSchedule table, which will contain the business hours that are available to count towards the SLA.这是一个使用WorkSchedule表的选项,该表将包含可用于计入 SLA 的营业时间。 To account for weekends and holidays, just do not insert records for these days into the WorkSchedule table.为了考虑周末和假期,不要将这些天的记录插入到WorkSchedule表中。

This solution also uses a "Tally" table aka numbers table in the due date calc.此解决方案还在到期日计算中使用“Tally”表,即数字表。 I also included debug output to help you see what is going on, so just comment out or uncomment any debug sections to see less/more info.我还包括调试输出以帮助您查看发生了什么,因此只需注释或取消注释任何调试部分即可查看更少/更多信息。

I used SQL temp tables in this example so that you can run it without messing up your current database schema, but you should replace with physical tables if you use this solution.我在这个例子中使用了 SQL 临时表,这样你就可以在不弄乱当前数据库模式的情况下运行它,但是如果你使用这个解决方案,你应该用物理表替换。

Test Data setups:测试数据设置:

CREATE TABLE #WorkSchedule(WorkStart datetime not null primary key, WorkEnd datetime not null);
GO
CREATE TABLE #Tally (N int not null primary key);
GO

--POPULATE TEST DATA
--populate Tally table
insert into #Tally (N)
select top 10000 N = row_number() over(order by o.object_id)
from sys.objects o cross apply sys.objects o2
;
go

--POPULATE WITH DUMMY TEST DATA
INSERT INTO #WorkSchedule(WorkStart, WorkEnd)
SELECT 
     workStart = dateadd(hour, 8, t.workDate) 
    , workEnd = dateadd(hour, 17, t.workDate) 
FROM (
    SELECT top 10000 workDate = dateadd(day, row_number() over(order by o.object_id), '2000-01-01')
    FROM sys.objects o cross apply sys.objects o2
) t 
--Exclude weekends from work schedule
WHERE datename(weekday, t.workDate) not in ('Saturday','Sunday')
;

GO

Code to calculate Due Date:计算到期日的代码:

SET NOCOUNT ON;
DECLARE @startDate datetime;
DECLARE @SLA_timespan_mins int;

DECLARE @workStartDayOne datetime; 
DECLARE @SLA_Adjusted int;
DECLARE @dueDate datetime;

--SET PARAM VALUES HERE FOR TESTING TO ANY DATE/SLA TIMESPAN YOU WANT: 
SET @startDate = '2014-01-04 05:00'; --Saturday
SET @SLA_timespan_mins = 10 * 60 ; --10 hrs.

--get the info day 1, since your start date might be after the work start time.
select top 1 @workStartDayOne = s.WorkStart 
    --increase the SLA timespan mins to account for difference between work start and start time
    , @SLA_Adjusted = case when @startDate > s.WorkStart then datediff(minute, s.WorkStart, @startDate) else 0 end + @SLA_timespan_mins
from #WorkSchedule s
where s.WorkEnd > @startDate
    and s.WorkStart <> s.WorkEnd
order by s.WorkStart asc
;

--DEBUG info:
select 'Debug Info' as DebugInfo, @startDate AS StartDate, @workStartDayOne as workStartDayOne, @SLA_timespan_mins as SLA_timespan_mins, @SLA_Adjusted as SLA_Adjusted;

--now sum all the non work hours during that period and determine the additional mins that need added.
;with cteWorkMins as
(
    SELECT TOP (@SLA_Adjusted)
          s.WorkStart, s.WorkEnd
        , WorkMinute = dateadd(minute, t.N, cast(s.WorkStart as datetime))
        , t.N as MinuteOfWorkDay
        , RowNum = row_number() over(order by s.WorkStart, t.N)
    FROM #WorkSchedule s
        INNER JOIN #Tally t 
            ON t.N between 1 and datediff(minute, s.WorkStart, s.WorkEnd)
    WHERE s.WorkStart >= @workStartDayOne
    ORDER BY s.WorkStart, t.N
)
/**/
SELECT @dueDate = m.WorkMinute 
FROM cteWorkMins m 
WHERE m.RowNum = @SLA_Adjusted 
--*/
/**
--DEBUG: this query will show every minute that is accounted for during the Due Date calculation.
SELECT m.*
FROM cteWorkMins m 
--WHERE m.RowNum = @SLA_Adjusted 
ORDER BY m.WorkMinute
--*/
;

select @dueDate as DueDate;
GO

Test Cleanup:测试清理:

IF object_id('TEMPDB..#WorkSchedule') IS NOT NULL
DROP TABLE #WorkSchedule;
GO
IF object_id('TEMPDB..#Tally') IS NOT NULL
DROP TABLE #Tally;

GO

as I understood from your question, what you need is as follow正如我从你的问题中了解到的,你需要的是如下

  1. You have given start date and number of minutes added to it, then you need to get the due date您已提供开始日期和添加的分钟数,然后您需要获取截止日期
  2. To get the due date, you need to exclude the holidays and the due date should be during business day要获得截止日期,您需要排除假期,截止日期应在工作日内

here is what you can do这是你可以做的

declare @start datetime,
        @min int,
        @days int

set @start= '28 Dec 2014'
set @min = 2200 

-- get the number of days
set @days=datediff(day,@start,dateadd(minute,@min,@start))

-- get the due date
select max(Date)
from
    (select row_number() over( order by t.Id)-1 as Id,t.Date 
     from DateMetadata t
     inner join BusinessDays b on Day(t.Date) = b.Day
     where t.Date > = @start and not exists(select 1 from Holidays h 
                      where h.Day=Day(t.Date)
                      and h.Month=Month(t.Date))) as p
where p.Id < @days

Note :that DateMetadata table you will setup it in your database once注意:您将在数据库中设置一次 DateMetadata 表

the setup for the above code :上述代码的设置:

create table Holidays(Id int identity(1,1),
                      Name nvarchar(50),
                      Day int,
                      Month int)
create table BusinessDays(Id int identity(1,1),
                           Name nvarchar(20),
                           Day int)

-- i am putting some days that are known, 
--  it depends on you to define which holidays you want
insert into Holidays (Name,Day,Month) values('Christmas',25,12)
insert into Holidays(Name,Day,Month) values('New Year',31,12)
insert into Holidays(Name,Day,Month) values('Valentine',14,2)
insert into Holidays(Name,Day,Month) values('Mothers day',21,3)
insert into Holidays(Name,Day,Month) values('April fools day',1,4)

-- i am assuming that the business days are from monday till friday and 
--  saturday and sunday are off days
insert into BusinessDays(Name,Day) values ('Monday',1)
insert into BusinessDays(Name,Day) values('Tuesday',2)
insert into BusinessDays(Name,Day) values('Wednesday',3)
insert into BusinessDays(Name,Day) values('Thursday',4)
insert into BusinessDays(Name,Day) values('Friday',5)

this table is needed and you will setup it once需要此表,您将设置一次

-- set up a table that contains all dates from now till 2050 for example
-- and you can change the value of 2050 depending on your needs
-- this table you will setup it once
create table DateMetadata(Id int identity(1,1),
                          Date datetime)

declare @date datetime
set @date='01 Jan 2014'
while @date < '31 Dec 2050'
begin
   insert into DateMetadata(Date) values(@date)
   set @date = @date + 1
end

here a working DEMO这是一个工作演示

if you need any explanation, i am ready如果你需要任何解释,我准备好了

hope it will help you希望它会帮助你

I created a function to calculate due date from the table, once it's populated as per Beth's and others' approaches (various similar methods for doing this, as you can see -- it only took me about an hour to think about all the UK holidays and populate the table including Easter dates up to 2029 without using these exact guides).我创建了一个函数来计算表格中的截止日期,一旦按照 Beth 和其他人的方法填充它(执行此操作的各种类似方法,如您所见——我只花了大约一个小时来考虑所有英国假期并在不使用这些确切指南的情况下填充表格,包括直到 2029 年的复活节日期)。

Note that my table contains SLA in business hours (8 hours in a normal day, 5 days in a normal week), your business hours may vary but you can amend this easily, just make sure your business hours are set the same for both the SLA table and the function below.请注意,我的表格包含营业时间的 SLA(正常一天 8 小时,正常一周 5 天),您的营业时间可能会有所不同,但您可以轻松修改,只需确保您的营业时间设置为相同SLA 表和下面的函数。

Code below is T-SQL (written in SSMS v17.8.1)下面的代码是 T-SQL(用 SSMS v17.8.1 编写)

CREATE FUNCTION [JIRA].[Fn_JIRA_Due_Date] (
    @CreatedDate DATETIME, @SLA_Business_Hours INTEGER
) RETURNS DATETIME
AS
-- SELECT [JIRA].[Fn_JIRA_Due_Date]('2019-12-28 08:00:00', 24)

/* 

baldmosher™
2019-03-25

* Function returns the DueDate for a JIRA ticket, based on the CreatedDate and the SLA (based on the Issue Type, or the Epic for Tasks) and business hours per date (set in [JIRA].[Ref_JIRA_Business_Hours])
* Called by IUP to store this at the time the ticket is loaded
* Can only consider SLA in Business Hours:
    * <24hrs calendar = <8hrs business
    * =24hrs calendar =  8hrs business
    * >24hrs calendar =  8hrs business * business days

*/


BEGIN

    IF @CreatedDate IS NULL OR @SLA_Business_Hours IS NULL RETURN NULL;

    DECLARE @SLA_Hours_Remaining SMALLINT = @SLA_Business_Hours;

    --SET DATEFIRST 1;
    DECLARE @DueDate DATETIME;
    DECLARE @BusHrsStart DECIMAL(18,10) = 8                         ; -- start of Business Hours (8am)
    DECLARE @BusHrsClose DECIMAL(18,10) = 16                        ; -- close of Business Hours (4pm)
    --DECLARE @WkndStart DECIMAL(18,10) = 6                         ; -- start of weekend (Sat)
    DECLARE @Hours_Today SMALLINT                                   ; -- # hours left in day to process ticket

    -- PRINT 'Created ' + CAST(CAST(@CreatedDate AS DATE) AS VARCHAR(10)) + ' ' + CAST(CAST(@CreatedDate AS TIME) AS VARCHAR(8))

    --!!!! extend to the next whole hour just to simplify reporting -- need to work on fixing this eventually
    SET @CreatedDate = DATEADD(MINUTE,60-DATEPART(MINUTE,@CreatedDate),@CreatedDate)
    -- PRINT 'Rounded ' + CAST(CAST(@CreatedDate AS DATE) AS VARCHAR(10)) + ' ' + CAST(CAST(@CreatedDate AS TIME) AS VARCHAR(8))


--check if created outside business hours and adjust CreatedDate to start the clock first thing at the next business hours start of day (days are checked next)
    IF DATEPART(HOUR,@CreatedDate) < @BusHrsStart 
    --created before normal hours, adjust @CreatedDate later to @BusHrsStart same day
        BEGIN
        SET @CreatedDate = DATEADD(HOUR,@BusHrsStart,CAST(CAST(@CreatedDate AS DATE) AS DATETIME))
        END

    IF DATEPART(HOUR,@CreatedDate) >= @BusHrsClose
    --created after normal hours, adjust @CreatedDate to @BusHrsStart next day
        BEGIN
        SET @CreatedDate = DATEADD(HOUR,@BusHrsStart,CAST(CAST(@CreatedDate+1 AS DATE) AS DATETIME))
        --adjust CreatedDate to start the clock the next day with >0 business hours (i.e. extend if it falls on a weekend or holiday)
        SET @CreatedDate = CAST(@CreatedDate AS DATE)
        StartNextWorkingDay:
        IF (SELECT TOP(1) [Business_Hours] FROM [JIRA].[Ref_JIRA_Business_Hours] b WHERE b.[Date] = @CreatedDate ORDER BY [Date]) = 0 
            BEGIN 
            SET @CreatedDate = DATEADD(DAY,1,@CreatedDate)
            GOTO StartNextWorkingDay
            END
            --DATEADD(DAY, DATEDIFF(DAY,0,@CreatedDate+7)/7*7,0);  -- midnight, Monday next week
        SET @CreatedDate = DATEADD(HOUR,@BusHrsStart,@CreatedDate);  -- BusHrsStart
        END
    -- PRINT 'Started ' + CAST(CAST(@CreatedDate AS DATE) AS VARCHAR(10)) + ' ' + CAST(CAST(@CreatedDate AS TIME) AS VARCHAR(8))

--third, check the business hours for each date from CreatedDate onwards to determine the relevant DueDate
    SET @DueDate = @CreatedDate
    -- PRINT 'SLA Hrs ' + CAST(@SLA_Hours_Remaining AS VARCHAR(2))
    SET @Hours_Today = @BusHrsStart + (SELECT TOP(1) [Business_Hours] FROM [JIRA].[Ref_JIRA_Business_Hours] b WHERE b.[Date] = CAST(@DueDate AS DATE) ORDER BY [Date]) - DATEPART(HOUR, @CreatedDate)
    -- PRINT 'Hrs Today ' + CAST(@Hours_Today AS VARCHAR(2))
    DueNextWorkingDay:
    IF @SLA_Hours_Remaining > @Hours_Today
        BEGIN
        -- PRINT 'Due another day'
        SET @SLA_Hours_Remaining = @SLA_Hours_Remaining - @Hours_Today            --adjust remaining time after today's hours
        SET @Hours_Today = (SELECT TOP(1) [Business_Hours] FROM [JIRA].[Ref_JIRA_Business_Hours] b WHERE b.[Date] = CAST(@DueDate AS DATE) ORDER BY [Date])
        -- PRINT 'SLA Hrs ' + CAST(@SLA_Hours_Remaining AS VARCHAR(2))
        -- PRINT 'Hrs Today ' + CAST(@Hours_Today AS VARCHAR(2))
        SET @DueDate = DATEADD(DAY,1,DATEADD(HOUR,@BusHrsStart,CAST(CAST(@DueDate AS DATE) AS DATETIME)))              --adjust DueDate to first thing next day
        END
    IF @SLA_Hours_Remaining <= @Hours_Today
        BEGIN
        -- PRINT 'Due today'
        SET @DueDate = DATEADD(HOUR,@SLA_Hours_Remaining,@DueDate)
        END
    ELSE
        BEGIN
        GOTO DueNextWorkingDay
        END

    -- PRINT 'DueDate ' + CAST(CAST(@DueDate AS DATE) AS VARCHAR(10)) + ' ' + CAST(CAST(@DueDate AS TIME) AS VARCHAR(8))

    RETURN @DueDate

END

GO

Table for SLAs: SLA 表:

CREATE TABLE [JIRA].[Ref_JIRA_SLAs](
    [SLA_SK] [SMALLINT] IDENTITY(1,1) NOT NULL,
    [Project] [VARCHAR](20) NULL,
    [Issue_Type] [VARCHAR](50) NULL,
    [Epic_Name] [VARCHAR](50) NULL,
    [SLA_Business_Hours] [SMALLINT] NULL,
    [Comments] [VARCHAR](8000) NULL
) ON [PRIMARY] WITH (DATA_COMPRESSION = PAGE)
GO

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 用SQL计算营业时间 - Calculating Business Hours in SQL Tableau:不包括周末、非营业时间和节假日的时差 - Tableau: time difference excluding weekends, outside business hours, and holidays 根据营业时间而不是总时间计算处理时间 - Calculating processing time based on business hours instead of total hours 计算两个日期之间的秒数,包括营业时间(节假日除外),开始时间08:30 - Calculate seconds between two dates including business hours, excluding holidays, start hour 08:30 存储开放时间/节假日 - Storing Open Hours/Holidays SQL - 计算分区中最早日期以来的小时数 - SQL - calculating hours since the earliest date in a partition 从日期开始的下一个工作日,包括Oracle SQL中的美国假期-无pl / sql代码 - Next Business day from a date including US Holidays in Oracle SQL - no pl/sql code 在给定日期添加N个工作日,以跳过SQL DB2中的假期,异常和周末 - Add N business days to a given date skipping holidays, exceptions and weekends in SQL DB2 计算假期:Oracle中给定日期范围查询中的周六和周日数 - Calculating holidays: number of saturdays and sundays within the given date range query in Oracle 在周五或周一为假日时计算周六和周日营业日期 - Calculating Saturday and Sunday Business Date when Friday or Monday are a Holiday
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM