我正在寻找一个SQL服务器功能,它可以计算2个给定日期时间值之间的小时数,但不包括星期五下午6点到星期一早上6点之间的小时数。
我希望能够将此作为自定义日期使用,但也可以作为自定义日期添加(例如,周五下午4点至下午5点,将在周一上午9点后返回)
我目前根据工作日的数字排除星期六/星期日,但这并不考虑周五/周一时间。
答案 0 :(得分:2)
这使用数字表。用参数调整周末开始/结束:
declare @d1 as datetime = '2018-06-01 05:30:00'
, @d2 as datetime = '2018-06-18 19:45:00'
, @FridayWE as int = 18 --6pm
, @MondayWS as int = 6 --6am
;WITH x AS (SELECT n FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(n))
select count(*) as HoursBetweenDatetimes
from (
SELECT dateadd(hour, ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n, dateadd(hour, datediff(hour, 0, @d1), 0)) as [DateHour]
FROM x ones, x tens, x hundreds, x thousands
) a
where not ((DATEPART(dw,[DateHour]) = 6 and DATEPART(hour,[DateHour]) >= @FridayWE)
or (DATEPART(dw,[DateHour]) = 7 )
or (DATEPART(dw,[DateHour]) = 1 )
or (DATEPART(dw,[DateHour]) = 2 and DATEPART(hour,[DateHour]) < @MondayWS))
and [DateHour] < @d2
答案 1 :(得分:1)
这是您可以使用的另一个选项,带有日历表。
这是日历表的生成。对于这种情况,它从星期一到星期五,从早上9点到下午6点,每行一天(这可以是常规日历表的附加列)只有几天。
IF OBJECT_ID('tempdb..#WorkingCalendar') IS NOT NULL
DROP TABLE #WorkingCalendar
CREATE TABLE #WorkingCalendar (
StartDateTime DATETIME,
EndDateTime DATETIME)
SET DATEFIRST 1 -- 1: Monday, 7: Sunday
DECLARE @StartDate DATE = '2018-01-01'
DECLARE @EndDate DATE = '2025-01-01'
;WITH RecursiveDates AS
(
SELECT
GeneratedDate = @StartDate
UNION ALL
SELECT
GeneratedDate = DATEADD(DAY, 1, R.GeneratedDate)
FROM
RecursiveDates AS R
WHERE
R.GeneratedDate < @EndDate
)
INSERT INTO #WorkingCalendar (
StartDateTime,
EndDateTime)
SELECT
StartDateTime = CONVERT(DATETIME, R.GeneratedDate) + CONVERT(DATETIME, '09:00:00'),
EndDateTime = CONVERT(DATETIME, R.GeneratedDate) + CONVERT(DATETIME, '18:00:00')
FROM
RecursiveDates AS R
WHERE
DATEPART(WEEKDAY, R.GeneratedDate) BETWEEN 1 AND 5 -- From Monday to Friday
OPTION
(MAXRECURSION 0)
这是计算2个日期时间之间的时差的查询。您可以在所有3个地方(HOUR
,MINUTE
等)更改所需内容的SECOND
,结果将以该单位显示。
DECLARE @FromDate DATETIME = '2018-06-15 18:00:00'
DECLARE @ToDate DATETIME = '2018-06-18 10:00:00'
;WITH TimeDifferences AS
(
-- Date completely covered
SELECT
Difference = DATEDIFF(
HOUR,
W.StartDateTime,
W.EndDateTime)
FROM
#WorkingCalendar AS W
WHERE
W.StartDateTime >= @FromDate AND
W.EndDateTime <= @ToDate
UNION ALL
-- Filter start date partially covered
SELECT
Difference = DATEDIFF(
HOUR,
@FromDate,
CASE WHEN W.EndDateTime > @ToDate THEN @ToDate ELSE W.EndDateTime END)
FROM
#WorkingCalendar AS W
WHERE
@FromDate BETWEEN W.StartDateTime AND W.EndDateTime
UNION ALL
-- Filter end date partially covered
SELECT
Difference = DATEDIFF(
HOUR,
CASE WHEN W.StartDateTime > @FromDate THEN W.StartDateTime ELSE @FromDate END,
@ToDate)
FROM
#WorkingCalendar AS W
WHERE
@ToDate BETWEEN W.StartDateTime AND W.EndDateTime
)
SELECT
Total = SUM(T.Difference)
FROM
TimeDifferences AS T
这种方法会从日历表中考虑每一天,因此,如果某一天您减少了工作时间(或者假期中没有时间),那么结果会考虑它。
您可以使用此查询添加小时数。基本上按小时分割每个日历范围,然后使用行号来确定要添加的小时数。在这种情况下,您无法简单地更改HOUR
的{{1}},如果您需要,可能需要进行一些调整。
MINUTE
您可以使用类似的逻辑来减少小时数,方法是创建行号,其中行的日期时间早于提供的日期时间(而不是之后)。