SQL Server 2012: функция DATEDIFF с точки зрения лет, дней и месяцев - PullRequest
0 голосов
/ 17 ноября 2018

Я использую функцию DATEDIFF в SQL Server 2012. У меня есть две даты, 2015-01-01 и current_date.Мне нужно DATEDIFF в терминах Лет, Месяцев и Дней между этими двумя датами.Ниже приведены мои заявления:

SELECT DATEDIFF(YY, '2015-01-01', GETDATE()) AS 'Years'
SELECT DATEDIFF(MM, '2015-01-01', GETDATE()) AS 'Months'
SELECT DATEDIFF(DD, '2015-01-01', GETDATE()) AS 'Days'

Результат, который я получаю: Годы = 3, Месяцы = 46, Дни = 1416

Почему в месяцах и днях добавляется дополнительный год?

Ответы [ 3 ]

0 голосов
/ 17 ноября 2018

Возможно, немного излишним, но если вы открыты для TVF

Пример

Declare @YourTable table (SomeDate date)
Insert Into @YourTable values 
('2015-01-01')

Select A.SomeDate
      ,B.*
 From  @YourTable A
 Cross Apply [dbo].[tvf-Date-Elapsed](SomeDate,GetDate()) B

Возвращает

SomeDate    Years   Months  Days    Hours   Minutes Seconds
2015-01-01  3       10      16      8       22      40

Функция при наличии интереса

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')
0 голосов
/ 17 ноября 2018

Мой взгляд на вдохновенный ответ @ JohnCappelletti

CREATE FUNCTION [dbo].[tvf_interval_parts] (@start DateTime, @cease DateTime)
Returns Table
RETURN
  SELECT
    *
  FROM
  (
    SELECT
      months / 12   AS years,
      months % 12   AS months
    FROM
    (
      SELECT
        CASE WHEN DATEADD(MONTH, months, @start) > @cease                           THEN months - 1
             WHEN DATEADD(MONTH, months, @start) = DATEADD(MONTH, months, @start-1) THEN months - 1
                                                                                    ELSE months     END   AS months
      FROM
      (
        SELECT DATEDIFF(MONTH, @start, @cease) AS months
      )
        provisional
    )
      adjusted
  )
    interim
  CROSS APPLY
  (
      SELECT
        milliseconds                         / (24 * 60 * 60 * 1000)  AS days,
        milliseconds % (24 * 60 * 60 * 1000) / (     60 * 60 * 1000)  AS hours,
        milliseconds % (     60 * 60 * 1000) / (          60 * 1000)  AS minutes,
        milliseconds % (          60 * 1000) / (               1000)  AS seconds,
        milliseconds % (               1000)                          AS milliseconds
      FROM
      (
        SELECT DATEDIFF_BIG(millisecond, DATEADD(MONTH, 12 * years + months, @start), @cease) AS milliseconds
      )
        provisional
  )
    remainder

Пример использования здесь: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=47b2d437c4cea78d182ce0f63772ef38

0 голосов
/ 17 ноября 2018

DATEDIFF() измеряет количество временных границ между двумя значениями даты / времени.

Таким образом, с помощью year он измеряет количество раз, когда год переворачивается (т. Е. Начинается новый год).

С помощью month он измеряет количество раз, когда месяц переворачивается (т. Е. Начинаются новые месяцы).

С day он измеряет количество смен дня (т. Е. Начинаются новые дни).

Все они независимы друг от друга.

Я бы порекомендовал вам , а не пытаться получить значение в годах / месяцах / днях. Это сложная проблема. Какое количество месяцев / дней между 28 февраля и 31 марта? Между 31 января и 28 февраля? Между 31 января и 31 марта? Они не складываются, что делает эту проблему сложной.

...