SQL Server计算从下午6点到周一早上6点之间的日期

时间:2018-06-18 08:14:34

标签: sql-server

我正在寻找一个SQL服务器功能,它可以计算2个给定日期时间值之间的小时数,但不包括星期五下午6点到星期一早上6点之间的小时数。

我希望能够将此作为自定义日期使用,但也可以作为自定义日期添加(例如,周五下午4点至下午5点,将在周一上午9点​​后返回)

我目前根据工作日的数字排除星期六/星期日,但这并不考虑周五/周一时间。

2 个答案:

答案 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个地方(HOURMINUTE等)更改所需内容的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

您可以使用类似的逻辑来减少小时数,方法是创建行号,其中行的日期时间早于提供的日期时间(而不是之后)。