排除周末并在SQL中获得时间

时间:2017-09-21 13:45:49

标签: sql sql-server

如何在这种情况下排除周末并仅在给定日期之间获得时间差异,下面是方案。

declare @d1 datetime, @d2 datetime
select @d1 = '2017-08-10 19:51:01.000',  @d2 = '2017-08-16 17:52:14.000'

select 
    Convert(varchar(5),datediff(s, @d1, @d2)/3600 - (datediff(wk, @d1, @d2) * 2) -
       case when datepart(dw, @d1) = 1 then 24 else 0 end + 
       case when datepart(dw, @d2) = 1 then 24 else 0 end )
         +':'+
         convert(Varchar(5),datediff(s, @d1, @d2)%3600/60  - (datediff(wk, @d1, @d2) * 2) -
       case when datepart(dw, @d1) = 1 then 24 else 0 end +
       case when datepart(dw, @d2) = 1 then 24 else 0 end)
          +':'+
         convert(Varchar(5),datediff(s, @d1, @d2)%60 - (datediff(wk, @d1, @d2) * 2) -
       case when datepart(dw, @d1) = 1 then 24 else 0 end +
      case when datepart(dw, @d2) = 1 then 24 else 0 end
         ) as hrs

2 个答案:

答案 0 :(得分:0)

一个想法是在@ d1之前或之后以及@ d2之前的上周一找到第一个星期一(如果我们说“周末”意味着星期六和星期日)。这是整周的数量。所以一周的时间是120(5天* 24小时)。然后我们将在上周一之后添加小时数直到@ d2。一个简单的案例在@ d2周的某一天将允许您在上周处理周末。同样,我们将计算@ d1和第一个星期一之前的小时数。

declare @d1 datetime, @d2 datetime
select @d1 = '2017-08-10 19:51:01.000',  @d2 = '2017-08-16 17:52:14.000'

declare @StartOfFirstWeekAfterStartDate date = cast(dateadd(day, case datepart(weekday, @d1)
    when 1 /* Sunday */ then -6
    when 2 /* Monday */ then 0
    when 3 /* Tuesday */ then 6
    when 4 /* Wendsday */ then 5
    when 5 /* Thursday */ then 4
    when 6 /* Friday */ then 3
    when 7 /* Saturday */ then 2
    end, @d1) as date),
    @StartOfLastWeekBeforeEndDate date = cast(dateadd(day, case datepart(weekday, @d2)
    when 1 /* Sunday */ then -6
    when 2 /* Monday */ then 0
    when 3 /* Tuesday */ then -1
    when 4 /* Wendsday */ then -2
    when 5 /* Thursday */ then -3
    when 6 /* Friday */ then -4
    when 7 /* Saturday */ then -5
    end, @d2) as date)

declare @NumberOfWorkdays int = datediff(week, @StartOfFirstWeekAfterStartDate, @StartOfLastWeekBeforeEndDate) * 5

declare @HoursWeekBefore int = case datepart(weekday, @d1)
    when 1 /* Sunday */ then 0
    when 2 /* Monday */ then 5 * 24 - datepart(hour, @d1)
    when 3 /* Tuesday */ then 4 * 24 - datepart(hour, @d1)
    when 4 /* Wendsday */ then 3 * 24 - datepart(hour, @d1)
    when 5 /* Thursday */ then 2 * 24 - datepart(hour, @d1)
    when 6 /* Friday */ then 1 * 24 - datepart(hour, @d1)
    when 7 /* Saturday */ then 0
    end

declare @HoursWeekAfter int = case datepart(weekday, @d2)
    when 1 /* Sunday */ then 5 * 24
    when 2 /* Monday */ then 0 * 24 + datepart(hour, @d2)
    when 3 /* Tuesday */ then 1 * 24 + datepart(hour, @d2)
    when 4 /* Wendsday */ then 2 * 24 + datepart(hour, @d2)
    when 5 /* Thursday */ then 3 * 24 + datepart(hour, @d2)
    when 6 /* Friday */ then 4 * 24 + datepart(hour, @d2)
    when 7 /* Saturday */ then 5 * 24
    end

declare @HoursDiff int = @HoursWeekBefore + @NumberOfWorkdays * 24 + @HoursWeekAfter

select
    @StartOfFirstWeekAfterStartDate,
    datepart(WEEKDAY, @StartOfFirstWeekAfterStartDate), -- Should always be Monday
    @StartOfLastWeekBeforeEndDate,
    datepart(WEEKDAY, @StartOfLastWeekBeforeEndDate), -- Should always be Monday
    @NumberOfWorkdays,
    datediff(week, @StartOfFirstWeekAfterStartDate, @StartOfLastWeekBeforeEndDate),
    @HoursWeekBefore,
    @HoursWeekAfter,
    @HoursDiff

上面的代码适合sp / udf使用。如果我们将所有这些计算放在一个表达式中,它将成为:

declare @d1 datetime, @d2 datetime
select @d1 = '2017-08-10 19:51:01.000',  @d2 = '2017-08-16 17:52:14.000'

select case datepart(weekday, @d1)
    when 1 /* Sunday */ then 0
    when 2 /* Monday */ then 5 * 24 - datepart(hour, @d1)
    when 3 /* Tuesday */ then 4 * 24 - datepart(hour, @d1)
    when 4 /* Wendsday */ then 3 * 24 - datepart(hour, @d1)
    when 5 /* Thursday */ then 2 * 24 - datepart(hour, @d1)
    when 6 /* Friday */ then 1 * 24 - datepart(hour, @d1)
    when 7 /* Saturday */ then 0
    end /* @HoursWeekBefore */
    + 
    datediff(week, 
        cast(dateadd(day, case datepart(weekday, @d1)
            when 1 /* Sunday */ then -6
            when 2 /* Monday */ then 0
            when 3 /* Tuesday */ then 6
            when 4 /* Wendsday */ then 5
            when 5 /* Thursday */ then 4
            when 6 /* Friday */ then 3
            when 7 /* Saturday */ then 2
            end, @d1) as date) /* @StartOfFirstWeekAfterStartDate */,
        cast(dateadd(day, case datepart(weekday, @d2)
            when 1 /* Sunday */ then -6
            when 2 /* Monday */ then 0
            when 3 /* Tuesday */ then -1
            when 4 /* Wendsday */ then -2
            when 5 /* Thursday */ then -3
            when 6 /* Friday */ then -4
            when 7 /* Saturday */ then -5
            end, @d2) as date) /* @StartOfLastWeekBeforeEndDate */) * 5 /* @NumberOfWorkdays */ * 24 
    + 
    case datepart(weekday, @d2)
        when 1 /* Sunday */ then 5 * 24
        when 2 /* Monday */ then 0 * 24 + datepart(hour, @d2)
        when 3 /* Tuesday */ then 1 * 24 + datepart(hour, @d2)
        when 4 /* Wendsday */ then 2 * 24 + datepart(hour, @d2)
        when 5 /* Thursday */ then 3 * 24 + datepart(hour, @d2)
        when 6 /* Friday */ then 4 * 24 + datepart(hour, @d2)
        when 7 /* Saturday */ then 5 * 24
        end /* @HoursWeekAfter */

请注意,上述计算取决于DATEFIRST设置。我写的假设周日是一周的第一天(即datepart(工作日,@今天)将返回2)。如果不是这种情况,则应调整case语句中的偏移量。 我也没有在这些时间处理分钟,因此小时计算有点粗糙。如果这是一个问题,您可以使用上述方法计算@ d1和@ d2之间的分钟数,并将其除以60.

答案 1 :(得分:0)

create function DateDiffWeekends(@a date, @b date)
returns int as
BEGIN
DECLARE @Result int
SELECT @Result = DateDiff(dd,@a,@b) 
               - DateDiff(ww,@a,@b)*2 
               - case DatePart(dw,@a) when 1 then 1 else 0 end 
               - case DatePart(dw,@b) when 7 then 1 else 0 end 
RETURN @Result
End

这是(类似于)我正在使用生产环境的功能。我将分析SELECT @Result区域中的四个公式中的每个公式正在做什么。

DateDiff(dd,@a,@b) 

这只是查找两个日期之间的天数。经典DateDiff。

- DateDiff(ww,@a,@b)*2 

这会查找两天之间的周数,并将其乘以2。这有效的原因是因为它计算了周休息的次数,而不是“7天段”的数量。例如,如果我选择星期五和随后的星期一的日期,DateDiff(ww,$Saturday,$Monday)将返回1周,即使它们仅在技术上相隔2天。

- case DatePart(dw,@a) when 1 then 1 else 0 end 

如果您选择星期日的开始日期,那么您将需要再休息一天。如果您的开始日是星期六,那么它将在不同的一周,所以之前的声明将照顾它。

- case DatePart(dw,@b) when 7 then 1 else 0 end 

如果您选择星期六的结束日期,那么您还需要从结果中休息一天。如果你的结束日是星期天,它将再次出现在不同的一周。

如果你想测试/玩它,这是一个SQLFiddle

编辑:我刚注意到你还要求时间。我将在这里留下这个答案,以防它对其他人有用,但它可能不适用于你的情况。