dateiff总是比我需要的数字少1

时间:2013-06-18 11:13:59

标签: sql sql-server tsql

我有以下似乎完美的工作,除了它总是比我需要的数量少1:

DECLARE @start_day DATETIME;
DECLARE @end_day DATETIME;
DECLARE @start_time DATETIME;
DECLARE @end_time DATETIME;

SET @start_day = '2013-06-03';
SET @end_day = '2013-06-07';

PRINT   DATEDIFF(d, @start_day, @end_day)
      - DATEDIFF(wk, @start_day, @end_day) * 2
      - CASE 
            WHEN DATEPART(dw, @start_day) != 7 AND DATEPART(dw, @end_day) = 7 THEN 1 
            WHEN DATEPART(dw, @start_day) = 7 AND DATEPART(dw, @end_day) != 7 THEN -1 
            ELSE 0
        END 

我应该

`5` for `2013-06-03` to `2013-06-07` but it's giving me `4`.
`5` for `2013-06-03` to `2013-06-08` but it's giving me `4`.
`5` for `2013-06-03` to `2013-06-09` but it's giving me `4`.
`6` for `2013-06-03` to `2013-06-10` but it's giving me `5`.

所以我的问题是:

我如何获得:

`2013-06-03` to `2013-06-07` to equal 5
`2013-06-03` to `2013-06-08` to equal 5
`2013-06-03` to `2013-06-09` to equal 5
`2013-06-03` to `2013-06-10` to equal 6

请注意,在结尾添加+1并不能解决问题!!!

3 个答案:

答案 0 :(得分:1)

Create table foo (
StartDate datetime not null,
EndDate datetime not null
)

insert into foo (StartDate, EndDate) values (N'2013-06-03', N'2013-06-07'),
(N'2013-06-03', N'2013-06-08'),
(N'2013-06-03', N'2013-06-09'),
(N'2013-06-03', N'2013-06-10')

SELECT 
    DATEDIFF(d, StartDate, EndDate)
    + CASE 
        WHEN DATEPART(dw, StartDate) <= 5 THEN 1 
        ELSE 0
        END
    - DATEDIFF(wk, StartDate, EndDate) * 2
    - CASE 
        WHEN DATEPART(dw, StartDate) != 7 AND DATEPART(dw, EndDate) = 7 THEN 1 
        WHEN DATEPART(dw, StartDate) = 7 AND DATEPART(dw, EndDate) != 7 THEN -1 
        ELSE 0
    END 
FROM foo

SqlFiddle

答案 1 :(得分:0)

如果您想要复制Excel的NETWORKDAYS,那么我在很久以前写过这个......

CREATE FUNCTION [dbo].[fnNetworkDays]
(
    @date1 SMALLDATETIME,
    @date2 SMALLDATETIME
)
RETURNS INT
AS
BEGIN
    DECLARE @ret INT,
            @dt1 INT,
            @dt2 INT,
            @dt3 INT,
            @neg INT,
            @wks INT,
            @dyo INT,
            @wkd INT,
            @take INT
    --Midnightise the dates
    SELECT @date1 = DATEADD(dd,0, DATEDIFF(dd,0,@date1)), @date2 = DATEADD(dd,0, DATEDIFF(dd,0,@date2))
    --Get integers to make the calcs easier
    SELECT @dt1 = CONVERT(INT,@date1),@dt2 = CONVERT(INT,@date2)

    IF @dt1 > @dt2
        BEGIN
        SET @neg = -1
        SET @dt3 = @dt1
        SET @dt1 = @dt2
        SET @dt2 = @dt3
        END
    ELSE
        SET @neg = 1

    SET @ret = @dt2 - @dt1 + 1
    SET @wks = FLOOR(@ret / 7)
    SET @dyo = @ret % 7
    SET @wkd = @dt1 % 7

    SELECT @take=CASE @wkd
        WHEN 0 THEN CASE WHEN @dyo = 6 THEN 1 ELSE 0 END
        WHEN 6 THEN CASE WHEN @dyo = 1 THEN 1 ELSE 0 END
        ELSE CASE WHEN @dyo = (6 - @wkd) THEN 1 ELSE CASE WHEN @dyo > (6 - @wkd) THEN 2 ELSE 0 END END
    END 

    SELECT @ret =  @neg * (@ret - @wks * 2 - @take) 

    RETURN @ret
END

可能过于复杂但有效。

答案 2 :(得分:0)

我宁愿使用带有计数表的COUNT。

SELECT COUNT(*)
FROM dbo.tTally
WHERE n BETWEEN DATEDIFF(dd, 0, @from) AND DATEDIFF(dd, 0, @to)
AND DATEPART(dw, DATEADD(dd, n, 0)) NOT IN (7, 1)

tally table