SQL Server:确定两个日期之间的年,月,周和日

时间:2018-04-18 15:24:19

标签: sql sql-server tsql

阅读本主题并建议使用DateDiff。我写了一个函数,但没有提供我想要的答案。客户现在想要完成清单需要多长时间。我有CreationDateCompletionDate。我需要知道它花了多少年,几个月,几周和几天。如果是2天,那么'2天'没有岁月。该功能扣除了年数,然后尝试检查月数,然后是周数,然后是天数。如果可用,仅给出结果。似乎DateDiff是问题......或者我不是理解DateDiff的问题。它甚至会返回一周的4天日期差异,这是没有意义的。它应该返回两个日期内的周数,而不是它开始时的关怀。

这是代码

ALTER FUNCTION [dbo].[DateRangeText]
    (@FromDate DATETIME, @ToDate DATETIME)
RETURNS VARCHAR(MAX)
AS
BEGIN
    DECLARE @Result AS VARCHAR(MAX);
    SET @Result = '';

    DECLARE @TmpS AS VARCHAR(MAX);
    SET @TmpS = '';

    DECLARE @Years AS INT;
    SET @Years = DATEDIFF(year, @FromDate, @ToDate);
    IF (@Years > 0)
    BEGIN
        IF (@Years = 1)
            SET @TmpS = ' Year ';
        ELSE
            SET @TmpS = ' Years ';

        SET @Result = @Result + CAST(@Years AS VARCHAR) + @TmpS;
        SET @ToDate = DATEADD(YEAR, -1 * @Years, @ToDate);
    END;

    DECLARE @Months AS INT;
    SET @Months = DATEDIFF(month, @FromDate, @ToDate);
    IF (@Months > 0)
    BEGIN
        IF (@Months = 1)
            SET @TmpS = ' Month ';
        ELSE
            SET @TmpS = ' Months ';

        SET @Result = @Result + CAST(@Months AS VARCHAR) + @TmpS;
        SET @ToDate = DATEADD(MONTH, -1 * @Months, @ToDate);
    END;

    DECLARE @Weeks AS INT;
    SET @Weeks = DATEDIFF(week, @FromDate, @ToDate);
    IF (@Weeks > 0)
    BEGIN
        IF (@Weeks = 1)
            SET @TmpS = ' Week ';
        ELSE
            SET @TmpS = ' Weeks ';

        SET @Result = @Result + CAST(@Weeks AS VARCHAR) + @TmpS;
        SET @ToDate = DATEADD(WEEK, -1 * @Weeks, @ToDate);
    END;

    DECLARE @Days AS INT;
    SET @Days = DATEDIFF(day, @FromDate, @ToDate);
    IF (@Days > 0)
    BEGIN
        IF (@Days = 1)
            SET @TmpS = ' Day ';
        ELSE
            SET @TmpS = ' Days ';

        SET @Result = @Result + CAST(@Days AS VARCHAR) + @TmpS;
        SET @ToDate = DATEADD(WEEK, -1 * @Days, @ToDate);
    END;

    IF (@Result = '')
        SET @Result = 'Same day';

    RETURN Rtrim(COALESCE(@Result,''));
END; 

2 个答案:

答案 0 :(得分:4)

由于您使用的是函数,请考虑以下表值函数。易于使用独立或包含在十字架上。

高效且准确,无需担心所有错误日期计算。

示例

Select * from [dbo].[tvf-Date-Elapsed] ('1991-09-12 21:00:00.000',GetDate())

<强>返回

Years   Months  Days    Hours   Minutes Seconds
26      7       5       13      47      11

TVF如有兴趣

CREATE FUNCTION [dbo].[tvf-Date-Elapsed] (@D1 DateTime,@D2 DateTime)
Returns Table
Return (
    with cteBN(N)   as (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
         cteRN(R)   as (Select Row_Number() Over (Order By (Select NULL))-1 From cteBN a,cteBN b,cteBN c),
         cteYY(N,D) as (Select Max(R),Max(DateAdd(YY,R,@D1))From cteRN R Where DateAdd(YY,R,@D1)<=@D2),
         cteMM(N,D) as (Select Max(R),Max(DateAdd(MM,R,D))  From (Select Top 12 R From cteRN Order By 1) R, cteYY P Where DateAdd(MM,R,D)<=@D2),
         cteDD(N,D) as (Select Max(R),Max(DateAdd(DD,R,D))  From (Select Top 31 R From cteRN Order By 1) R, cteMM P Where DateAdd(DD,R,D)<=@D2),
         cteHH(N,D) as (Select Max(R),Max(DateAdd(HH,R,D))  From (Select Top 24 R From cteRN Order By 1) R, cteDD P Where DateAdd(HH,R,D)<=@D2),
         cteMI(N,D) as (Select Max(R),Max(DateAdd(MI,R,D))  From (Select Top 60 R From cteRN Order By 1) R, cteHH P Where DateAdd(MI,R,D)<=@D2),
         cteSS(N,D) as (Select Max(R),Max(DateAdd(SS,R,D))  From (Select Top 60 R From cteRN Order By 1) R, cteMI P Where DateAdd(SS,R,D)<=@D2)

    Select [Years]   = cteYY.N
          ,[Months]  = cteMM.N
          ,[Days]    = cteDD.N
          ,[Hours]   = cteHH.N
          ,[Minutes] = cteMI.N
          ,[Seconds] = cteSS.N
          --,[Elapsed] = Format(cteYY.N,'0000')+':'+Format(cteMM.N,'00')+':'+Format(cteDD.N,'00')+' '+Format(cteHH.N,'00')+':'+Format(cteMI.N,'00')+':'+Format(cteSS.N,'00')
     From  cteYY,cteMM,cteDD,cteHH,cteMI,cteSS
)
--Max 1000 years
--Select * from [dbo].[tvf-Date-Elapsed] ('1991-09-12 21:00:00.000',GetDate())
--Select * from [dbo].[tvf-Date-Elapsed] ('2017-01-01 20:30:15','2018-02-05 22:58:35')

答案 1 :(得分:0)

除非我有时间再回到这里,否则我会花几周时间和闰年来解决问题。但是,这将为您提供所需的年,月和日:

DECLARE @FromDate DateTime
DECLARE @ToDate DateTime
DECLARE @years INT
DECLARE @months INT
DECLARE @days INT

-- just some sample dates for testing   
Set @FromDate = '01-01-2014'
Set @ToDate = GetDate()

SET @years = DATEDIFF(mm, @FromDate, @ToDate)/12
SET @months = DATEDIFF(mm, @FromDate, @ToDate)%12 - 1
SET @days = ABS(DATEDIFF(dd, DATEADD(mm,@months , DATEADD(yy, @years, @FromDate)), @ToDate))

DECLARE @YearsStr VarChar(20)
DECLARE @MonthsStr VarChar(20)
DECLARE @DaysStr VarChar(20)

SET @YearsStr = Case When @years > 0 Then Convert(varchar(10),@years) + ' Years, ' Else '' End
SET @MonthsStr = Case When @months > 0 Then Convert(varchar(10),@months) + ' Months, ' Else '' End
SET @DaysStr = Convert(varchar(10),@days) + ' Days '

SELECT @YearsStr + @MonthsStr + @DaysStr