[英]DATEDIFF between dates based on business hour (8 am - 5 pm) instead of total hours or days
I need to calculate the business hours (8am - 5pm) between different dates.我需要计算不同日期之间的营业时间(上午 8 点至下午 5 点)。 Here is the scenario: Tickets get assigned to employees ( Ticket_Submission
(DateTime)), then the employee creates a product ( Build_Date
(Datetime)), now sometimes in order to create a product a medication needs to be built ( Med_Date
(Datetime)).这是场景:票证被分配给员工( Ticket_Submission
(DateTime)),然后员工创建产品( Build_Date
(Datetime)),现在有时为了创建产品需要构建药物( Med_Date
(Datetime)) . In order to calculate the how long it took for the employee to create a product, I need to DATEDIFF
between Ticket_submission AND Build_Date
, however, if medication is involved, it had to be between Med_Date AND Build_Date
.为了计算员工创建产品所需的时间,我需要在Ticket_submission AND Build_Date
之间进行DATEDIFF
,但是,如果涉及药物,它必须在Med_Date AND Build_Date
之间。 It is OK to include weekends and holidays.可以包括周末和节假日。 The following helps me to get the difference in days:以下帮助我在几天内获得差异:
.....
,IIF((med_date = buid_date OR ticket_submission = build_date), 1
, IIF(med_date IS NULL OR med_date < ticket_submission , (DATEDIFF(dd, ticket_submission,build_date))
, DATEDIFF(dd, med_date, build_date))) AS buildcompletedate,….
This only gives me the number of days, also, I know that if instead of DD, I put hours I can get the total number of hours between the 2 dates.这只给了我天数,而且,我知道如果不是 DD,我把小时数放在我可以得到两个日期之间的总小时数。 But, how I can have these in business hours?但是,我怎么能在工作时间拥有这些呢?
I do appreciate your help.我很感激你的帮助。
ticketID Ticket_submission Med_Date Build_Date
1549392 2017-04-07 10:31:06:210 2017-04-08 11:31:06:210 2017-04-09 12:30:08:110
1751406 2017-06-06 4:30:08:200 2018-08-06 3:30:08:200 2018-09-10 3:30:08:200
2583870 2019-11-20 1:20:01:100 NULL 2019-11-23 2:20:01:100
To help construct test sample, here is a common table expression that constructs the test sample in-memory:为了帮助构建测试样本,下面是一个在内存中构建测试样本的通用表表达式:
; with Ticket (TicketID, Ticket_Submission, Med_Date, Build_Date)
AS
(
SELECT TicketID = 1549392, Ticket_Submission = CAST('2017-04-07 10:31:06:210' AS DATETIME2), Med_Date = CAST('2017-04-08 11:31:06:210' AS DATETIME2), Build_Date = CAST('2017-04-09 12:30:08:110' AS DATETIME2) UNION ALL
SELECT 1751406, CAST('2017-06-06 4:30:08:200' AS DATETIME2), CAST('2018-08-06 3:30:08:200' AS DATETIME2), CAST('2018-09-10 3:30:08:200 ' AS DATETIME2) UNION ALL
SELECT 2583870, CAST('2019-11-20 1:20:01:100' AS DATETIME2), CAST(NULL AS DATETIME2), CAST('2019-11-23 2:20:01:100' AS DATETIME2)
)
select
TicketID,
0 AS RoundedBusinessHoursBetweenDates /* Update with answer code */
from Ticket
TicketID RoundedBusinessHoursBetweenDates
-------- --------------------------------
1549392 10
1751406 307
2583870 20????
Med_Date
is NULL
then only the difference from ticket_submission till build_date对于第三行(TicketID 2583870),如果Med_Date
是NULL
,那么只有从 ticket_submission 到 build_date 的差异I am not sure your data is valid.我不确定您的数据是否有效。 I assume the date for the 2nd row should be 2018-09-10 15:30:08:200
as 2018-09-10 3:30:08:200
is not within working hours.我假设第二行的日期应该是2018-09-10 15:30:08:200
,因为2018-09-10 3:30:08:200
不在工作时间内。 Anyway, you'll need to calculate the hours in 3 separate parts.无论如何,您需要分 3 个单独的部分计算小时数。 The hours from the start DateTime to 5 pm and the hours from 8 am of the last date to the real last DateTime, plus the working hours in between.从开始 DateTime 到下午 5 点的小时数和从最后一个日期的上午 8 点到真正的最后一个 DateTime 的小时数,加上其间的工作时间。
It's not pretty, but here is the sample code.它不漂亮,但这里是示例代码。 The sum of these 3 columns is your total hours.这 3 列的总和就是您的总小时数。
declare @tblTemp table(ticketId int, ticket_submission datetime, med_date datetime, build_date datetime)
insert into @tblTemp
values(1549392,'2017-04-07 10:31:06:210','2017-04-08 11:31:06:210','2017-04-09 12:30:08:110'),
(1751406,'2017-06-06 16:30:08:200','2018-08-06 15:30:08:200','2018-09-10 15:30:08:200'),
(2583870,'2019-11-20 13:20:01:100',null,'2019-11-23 14:20:01:100')
select ticketId, datediff(hour, coalesce(med_date, ticket_submission), convert(varchar(10), coalesce(med_date, ticket_submission), 120) + ' 17:00:00') -- first day hours
,(datediff(day, coalesce(med_date, ticket_submission), build_date) - 1) * (17-8) -- hours in between
,datediff(hour, convert(varchar(10), build_date, 120) + ' 08:00:00', build_date) -- last day hours
from @tblTemp
To exclude weekends, see this so answer or this one .要排除周末,请参阅this so answer或this one 。 If you want to exclude weekends and holidays, you might need a calendar table.如果您想排除周末和节假日,您可能需要一个日历表。
Try this:尝试这个:
; with Ticket (TicketID, Ticket_Submission, Med_Date, Build_Date)
AS
(
SELECT TicketID = 1549392, Ticket_Submission = CAST('2017-04-07 10:31:06:210' AS DATETIME2), Med_Date = CAST('2017-04-08 11:31:06:210' AS DATETIME2), Build_Date = CAST('2017-04-09 12:30:08:110' AS DATETIME2) UNION ALL
SELECT 1751406, CAST('2017-06-06 4:30:08:200' AS DATETIME2), CAST('2018-08-06 3:30:08:200' AS DATETIME2), CAST('2018-09-10 3:30:08:200 ' AS DATETIME2) UNION ALL
SELECT 2583870, CAST('2019-11-20 1:20:01:100' AS DATETIME2), CAST(NULL AS DATETIME2), CAST('2019-11-23 2:20:01:100' AS DATETIME2)
)
select
TicketID,
CASE
WHEN DATEDIFF(Hour,ISNULL(Med_Date,ticket_submission),build_date)>24
THEN (DATEDIFF(Hour,ISNULL(Med_Date,ticket_submission),build_date)-15)/24
END AS DAYS,
CASE
WHEN DATEDIFF(Hour,ISNULL(Med_Date,ticket_submission),build_date)>24 AND (DATEDIFF(Hour,ISNULL(Med_Date,ticket_submission),build_date)-15)/24 >0
THEN DATEDIFF(Hour,ISNULL(Med_Date,ticket_submission),build_date) -(15 * DATEDIFF(DAY,ISNULL(Med_Date,ticket_submission),build_date))-9
ELSE DATEDIFF(Hour,ISNULL(Med_Date,ticket_submission),build_date) -(15 * DATEDIFF(DAY,ISNULL(Med_Date,ticket_submission),build_date))
END
from Ticket
The Total_Hours Column will Return the Total number of Columns Between the Two Days and the Days and Hours Column Return the Days and Hours Differences between those Columns. Total_Hours 列将返回两天之间的总列数,而天数和小时数列返回这些列之间的天数和小时数差异。
Hope this Code Works Successfully for your Rows and Sorry for my previous answer i misunderstood your Question.希望此代码对您的行成功运行,对于我之前的回答,我误解了您的问题,我深表歉意。
Anyway Thanks John Zabroski and Martin Smith不管怎样,谢谢约翰·扎布罗斯基和马丁·史密斯
Several aspects were analyzed to implement the solution.分析了几个方面以实施该解决方案。
by means of a function, it establishes the days related to the schedule通过 function,它建立了与时间表相关的天数
and if any of the days worked are holidays, evaluating each of the time ranges如果任何工作日是假期,则评估每个时间范围
already with these relations it is calculated by day how much I worked and calculates the total hours已经有了这些关系,它按天计算了我工作了多少并计算了总小时数
with the code you can understand it better使用代码您可以更好地理解它
CREATE FUNCTION TimeInBusiness
(
@StarDate as Datetime,
@EndDate as Datetime,
@Schedule NVARCHAR(MAX),
@HolyDay as varchar(3000)
)
RETURNS decimal(18,2)
AS
BEGIN
declare @Globalization as varchar(6)='en-US'
declare @Returnvalue as varchar(4000);
DECLARE @ListHolyDay TABLE(HolyDay Date);
DECLARE @ListDays TABLE(Day Date,DayWeek varchar(20),StarTime Time,EndTime Time);
INSERT INTO @ListHolyDay(HolyDay)
SELECT try_cast(value as date)
FROM STRING_SPLIT(@HolyDay, ',')
where try_cast(value as date) is not null
DECLARE @ListBusinessDay TABLE(DayWeek varchar(20),InveralTimeStar Time,InveralTimeEnd Time);
INSERT INTO @ListBusinessDay(DayWeek,InveralTimeStar,InveralTimeEnd)
SELECT DayWeek,cast(InveralTimeStar as time) as InveralTimeStar,cast(InveralTimeEnd as time) as InveralTimeEnd
FROM OPENJSON(@Schedule)
WITH (
DayWeek NVARCHAR(20) '$.Interval.DayWeek',
InveralTimeStar NVARCHAR(20) '$.Interval.InveralTimeStar',
InveralTimeEnd NVARCHAR(20) '$.Interval.InveralTimeEnd'
);
declare @SecondsHour as float=3600
declare @IntervalStarDate as Date
declare @IntervalEndDate as Date
set @IntervalStarDate=cast(@StarDate as date)
set @IntervalEndDate=cast(@EndDate as date)
declare @StarTime as varchar(8)=''
declare @EndTime as varchar(8)=''
WHILE (@IntervalStarDate<=@IntervalEndDate)
BEGIN
if (@IntervalStarDate<@StarDate)
begin
set @StarTime=FORMAT( @StarDate, 'HH:mm:ss', @Globalization )
end
else
begin
set @StarTime=FORMAT( @IntervalStarDate, 'HH:mm:ss', @Globalization )
end
if (@IntervalStarDate<@IntervalEndDate)
begin
set @EndTime='23:59:59'
end
else
begin
set @EndTime=FORMAT( @EndDate, 'HH:mm:ss', @Globalization )
end
INSERT INTO @ListDays(Day,DayWeek,StarTime,EndTime )VALUES (@IntervalStarDate, FORMAT( @IntervalStarDate, 'ddd', @Globalization ),cast(@StarTime as time),cast(@EndTime as time))
set @IntervalStarDate=DATEADD(Day,1,@IntervalStarDate)
END;
with ForDayTime as
(
select ListDays.Day,ListBusinessDay.DayWeek ,ListBusinessDay.InveralTimeStar,ListBusinessDay.InveralTimeEnd,
ListDays.StarTime,ListDays.EndTime,
CASE
WHEN ListBusinessDay.InveralTimeStar<=ListDays.StarTime THEN ListDays.StarTime
ELSE ListBusinessDay.InveralTimeStar
END as StarTimeDay
,
CASE
WHEN ListBusinessDay.InveralTimeEnd>=ListDays.EndTime THEN ListDays.EndTime
ELSE ListBusinessDay.InveralTimeEnd
END as EndTimeDay
from @ListDays as ListDays
inner join @ListBusinessDay as ListBusinessDay on ListDays.DayWeek =ListBusinessDay.DayWeek
where (ListDays.Day not in (select HolyDay from @ListHolyDay))
)
select
@Returnvalue=isnull(sum(datediff(SECOND, StarTimeDay,EndTimeDay)) /@SecondsHour,0)
from ForDayTime
where (StarTimeDay<EndTimeDay)
RETURN @Returnvalue;
END;
Example Use示例使用
declare @StarDate as Datetime='2020-04-10 10:00:00'
declare @EndDate as Datetime='2020-04-20 12:59:00'
DECLARE @Schedule NVARCHAR(MAX);
SET @Schedule = N'[
{"Interval": {"DayWeek": "Mon", "InveralTimeStar": "09:30", "InveralTimeEnd": "11:30"}},
{"Interval": {"DayWeek": "Mon", "InveralTimeStar": "13:30", "InveralTimeEnd": "16:30"}},
{"Interval": {"DayWeek": "Tue", "InveralTimeStar": "08:30", "InveralTimeEnd": "16:30"}},
{"Interval": {"DayWeek": "Wed", "InveralTimeStar": "08:30", "InveralTimeEnd": "16:30"}},
{"Interval": {"DayWeek": "Thu", "InveralTimeStar": "08:30", "InveralTimeEnd": "16:30"}},
{"Interval": {"DayWeek": "Fri", "InveralTimeStar": "08:30", "InveralTimeEnd": "12:30"}}
]';
declare @HolyDay as varchar(3000)='2020-04-16,2020-04-17'
select
dbo.TimeInBusiness('2020-04-10 10:00:00','2020-04-20 12:59:00',@Schedule,@HolyDay) as result,
dbo.TimeInBusiness('2020-04-10 10:00:00','2020-04-20 12:59:00',@Schedule,'') as result2,
dbo.TimeInBusiness('2020-04-01 10:00:00','2020-04-20 12:59:00',@Schedule,@HolyDay) as result
Go
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.