T-SQL |计算日期之间的小时数,但忽略周末的小时数,只计算 8-18 小时

T-SQL | Calculate the number of hours between dates but ignore the hours from Weekend and only count 8-18 hours

我正在尝试计算不包括周末的两个日期之间的差异,并且只计算从晚上 8 点到早上 6 点的时间。我想计算天数、小时数和分钟数的差异。

为此我有这个:

DECLARE @Start_Date DATETIME
DECLARE @End_Date DATETIME

SET @Start_Date = '2017-06-23 10:43:41.000'
SET @End_Date = '2017-06-27 11:58:52.000'

SELECT (DATEDIFF(dd, @Start_Date, @End_Date) + 1)
                -(DATEDIFF(wk, @Start_Date, @End_Date) * 2)
                -(CASE WHEN DATENAME(dw, @Start_Date) = 'Sunday' THEN 1 ELSE 0 END)
                -(CASE WHEN DATENAME(dw, @End_Date) = 'Saturday' THEN 1 ELSE 0 END) AS [Time to First Atualization- Days],
            datediff(hour, @Start_Date, @End_Date) - (datediff(wk, @Start_Date, @End_Date) * 48) -
                case when datepart(dw, @Start_Date)  = 1 then 1 else 0 end +
                case when datepart(dw, @End_Date)  = 1 then 1 else 0 end AS [Time to First Atualization- Hours],
                datediff(minute, @Start_Date, @End_Date) - (datediff(wk, @Start_Date, @End_Date) * 2880) -
                case when datepart(dw, @Start_Date)  = 1 then 1 else 0 end +
                case when datepart(dw, @End_Date)  = 1 then 1 else 0 end AS [Time to First Atualization- Minutes]

查询的天数return正确值但是计算小时数和分钟数是错误的...

我该如何解决这个问题?

谢谢!

我从头开始解决了一些问题,它似乎满足了您的所有需求,但如果有任何遗漏,您可以向我们反馈。

考虑到这是一个全新的开始,并且从不同的角度出发,您可能会从中发现某些技巧或想法。此外,它对我来说似乎更简单,但也许那是因为我正在审查自己的工作...

最后一点,我将依赖我之前读过的一个技巧,它以行方式应用 MINMAX,抽象示例:

SELECT MAX([value]) AS [MAX], MIN([value]) AS [MIN]
FROM (
VALUES (CURRENT_TIMESTAMP), (@Start_Date), (@End_Date), (NULL), (0)
) AS [data]([value])

首先,考虑计算开始和结束日期之外的时间量:

SELECT MinutesExcludingStartAndEndDays = MAX([value])
FROM (VALUES (0), ((DATEDIFF(DAY, @Start_Date, @End_Date) - 1) * 840)) AS [data]([value])

其次,计算开始日的时间,相对于晚上 8 点(或结束时间,如果这两天匹配):

SELECT MinutesOnStartDay = DATEDIFF(MINUTE, @Start_Date, MIN([value]))
FROM (VALUES (@End_Date), (DATETIMEFROMPARTS(YEAR(@Start_Date), MONTH(@Start_Date), DAY(@Start_Date), 20, 0, 0, 0))) AS [data]([value])

第三与第二非常相似,但请注意,如果开始和结束日期相同,我们不应同时计算第二和第三。我决定在 third:

中用 CASE 语句来处理这个问题
SELECT MinutesOnEndDayIfNotStartDay = CASE DATEDIFF(DAY, @Start_Date, @End_Date) WHEN 0 THEN 0 ELSE DATEDIFF(MINUTE, MAX([value]), @End_Date) END
FROM (VALUES (@Start_Date), (DATETIMEFROMPARTS(YEAR(@End_Date), MONTH(@End_Date), DAY(@End_Date), 6, 0, 0, 0))) AS [data]([value])

第四,如果开始日期或结束日期落在周末,则应将其推离那里:

DECLARE @Mod int

SET @Mod = CONVERT(int, @Start_Date) % 7
IF @Mod IN (5, 6)
    SET @Start_Date = DATEADD(DAY, CASE @Mod WHEN 5 THEN 2 WHEN 6 THEN 1 ELSE 0/0 END, DATETIMEFROMPARTS(YEAR(@Start_Date), MONTH(@Start_Date), DAY(@Start_Date), 6, 0, 0, 0))

SET @Mod = CONVERT(int, @End_Date) % 7
IF @Mod IN (5, 6)
    SET @End_Date = DATEADD(DAY, CASE @Mod WHEN 5 THEN -1 WHEN 6 THEN -2 ELSE 0/0 END, DATETIMEFROMPARTS(YEAR(@End_Date), MONTH(@End_Date), DAY(@End_Date), 20, 0, 0, 0))

最后,关于将周末完全包含在目标期间内的问题,请看一下 this question,从那里的投票来看,我只能猜测他们已经解决了。