【问题标题】:How can I get a real difference between two dates in months?我怎样才能在几个月内得到两个日期之间的真正差异?
【发布时间】:2023-01-30 00:59:38
【问题描述】:

我的问题是,当我将日期范围设置如下

DECLARE @startdate DATETIME2 = '2023-01-31 08:00:00.0000000';  
DECLARE @enddate   DATETIME2 = '2023-02-01 08:00:00.0000000';   
SELECT DATEDIFF(month, @startdate, @enddate)

结果是一个。

【问题讨论】:

  • 那么你在这里期待什么?二月和一月1个月不同。 DATEDIFF 测量滴答声和月份勾选在这两天之间(当月份从一月变为二月时)一次。
  • 你的意思是real不同?需要什么精度?什么范围,例如几千年来?参考月份有多长? 28、29、30 或 31 天?闰秒重要吗?我们需要了解更多信息以帮助计算。
  • 在指定的日期范围内,月份为零。如果我们将 @enddate 替换为“2023-02-28 08:00:00.0000000”,则正确值为 1 个月。 (年份不是闰年)
  • 您可以将“正确值”指定为算法吗?在一天的同一时间月末到月末看起来很容易。我们假设任何少于 28 天的时间都是零 L. Kvri 月。 2023-01-15 00:00:00 之后的一个月 L. Kvri 恰好是多少?是二月一日之后的 14 天还是最后一天之前的 16 天?

标签: sql-server date tsql difference


【解决方案1】:

也许您正在寻找的更多,但这是一个表值函数。如果您的数据在表中,可以单独调用或在 CROSS APPLY 内调用

例子

DECLARE @startdate DATETIME2 = '2023-01-31 08:00:00.0000000';  
DECLARE @enddate   DATETIME2 = dateadd(month,6,getdate()) --'2023-02-01 08:00:00.0000000';   

Select * 
From [dbo].[tvf-Date-Elapsed](@startdate,@enddate)

结果

Years   Months  Days    Hours   Minutes Seconds
0       5       24      3       2       49

感兴趣的功能

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())

【讨论】:

  • 你好谢谢!在我看来它运作良好。但我不完全知道它是如何工作的。你能给我们解释一下吗?请只关注月份。
  • 嗨 John Cappelletti,还有一件事,cteBN 和 cteRN 是什么意思?
  • @L.Kvri 非常简单,我们创建了一个临时数字/理货表。然后我们对 Year (cteYY)、Month (cteMM)、Day (cteDD) 进行最大观察次数...您当然可以注释掉/删除不必要的 CTE,如 cteDD、cteHH、cteMI 和 cteSS
  • @L.Kvri cteBN 是 cteBaseNumber,它只是 10 位数字/行。 cteRN 或 cteRowNumber 本质上是一个 CROSS JOIN,它将 10 行变成 1000 (10*10*10)
  • 不错的解决方案,但不适用于闰年。尝试使用 2000-01-31 和 2000-02-01 的日期,看看它得出的错误答案是 1 天而不是 2 天。
【解决方案2】:

是的...我刚刚测试过。它适用于闰年。我道歉。再次,不确定我发布该错误时在想什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-07
    • 1970-01-01
    • 1970-01-01
    • 2022-12-12
    • 2016-02-11
    • 2022-08-02
    • 2018-11-08
    • 1970-01-01
    相关资源
    最近更新 更多