最近发现了一些东西(当然,我的错误是没有阅读文档),这让我对SQLServer的DATEDIFF功能感到震惊;它计算两个指定日期之间的间隔边界数。
这意味着我可以询问01 Jan 23:57
和01 Jan 23:59
之间的天数,它会返回0,但如果我要求01 Jan 23:59
和{{1}之间的天数它会告诉我他们之间有一天。时间跨度相同:2分钟,但突然一个是0天的差异,一个是1天的差异
来自Oracle和.Net背景我可以看到我假设TSQL中的DATEDIFF等效地工作(即准备一个时间跨度然后将其四舍五入到指定的时间间隔),我犯了一个严重的错误,但是替代方案是什么?
如果我想准确地找出小数位,两个日期之间有多少年,我该如何在SQLServer中完成?我不希望从1月1日到12月31日的结果返回0年,但是2000年12月31日到2002年1月1日返回2年,因为这些是严重错误并且距离0.997和1.005(不是确切的计算)它们应该更多可能是......
答案显然不是DATEDIFF的天数除以365.0,不仅因为dateiff通常是“错误的”,即使是DAYS(根据我的2分钟例子),也因为并非总是365天年。几个月相同 - >它们并不总是指定的间隔长度,因此将天数除以31(或30,29或28)是没有意义的。出于同样的原因,我不能做简单的02 Jan 00:01
数学
答案 0 :(得分:1)
更新:此代码不包含DST。
您还可以构建自己的代码,这将计算日期之间的差异并将其投入使用。
DECLARE @dateFrom DATETIME, @dateTo DATETIME
SET @dateFrom = '2000-12-31 23:59'
SET @dateTo = '2002-01-02 00:01'
SELECT DATEDIFF(YEAR, DATEADD(year,DATEDIFF(year,0,DATEADD(year,1,@dateFrom)),0), DATEADD(year,DATEDIFF(year,0,@dateTo),0))
+ CASE WHEN YEAR(@dateFrom) < YEAR(@dateTo) THEN (DATEDIFF(MINUTE, @dateFrom, CAST(YEAR(@dateFrom) AS CHAR(4))+'-12-31 23:59') + 1) / (1.0*DATEDIFF(minute, CAST(YEAR(@dateFrom) AS CHAR(4))+'-01-01 00:00', CAST(YEAR(@dateFrom) AS CHAR(4))+'-12-31 23:59') + 1)
+ (DATEDIFF(MINUTE, CAST(YEAR(@dateTo) AS CHAR(4))+'-01-01 00:00',@dateTo ) + 1) / (1.0*DATEDIFF(minute, CAST(YEAR(@dateTo) AS CHAR(4))+'-01-01 00:00', CAST(YEAR(@dateTo) AS CHAR(4))+'-12-31 23:59') + 1)
ELSE (DATEDIFF(MINUTE,@dateFrom, @dateTo) + 1) / (1.0*DATEDIFF(minute, CAST(YEAR(@dateTo) AS CHAR(4))+'-01-01 00:00', CAST(YEAR(@dateTo) AS CHAR(4))+'-12-31 23:59') + 1) END
--Result: 1.002745428591627
此代码需要注释,所以:
+1
需要获得日期之间的确切分钟数。
这用于计算年份的分钟数。
(1.0*DATEDIFF(minute, CAST(YEAR(@dateTo) AS CHAR(4))+'-01-01 00:00', CAST(YEAR(@dateTo) AS CHAR(4))+'-12-31 23:59') + 1)
这给了我们今年的开始。
DATEADD(year,DATEDIFF(year,0,@dateTo),0)
这段代码正在计算@dateFrom
和@dateTo
之间的整年。
DATEDIFF(YEAR, DATEADD(year,DATEDIFF(year,0,DATEADD(year,1,@dateFrom)),0), DATEADD(year,DATEDIFF(year,0,@dateTo),0))
这是计算“部分”年份。我们正在计算到年底还有多少分钟。
(DATEDIFF(MINUTE, @dateFrom, CAST(YEAR(@dateFrom) AS CHAR(4))+'-12-31 23:59') + 1) / (1.0*DATEDIFF(minute, CAST(YEAR(@dateFrom) AS CHAR(4))+'-01-01 00:00', CAST(YEAR(@dateFrom) AS CHAR(4))+'-12-31 23:59') + 1)
与上面的内容类似,但适用于@dateTo
。
(DATEDIFF(MINUTE, CAST(YEAR(@dateTo) AS CHAR(4))+'-01-01 00:00',@dateTo ) + 1) / (1.0*DATEDIFF(minute, CAST(YEAR(@dateTo) AS CHAR(4))+'-01-01 00:00', CAST(YEAR(@dateTo) AS CHAR(4))+'-12-31 23:59') + 1)
在这里,我们计算的是@dateFrom
和@dateTo
年份相同的年份。
(DATEDIFF(MINUTE,@dateFrom, @dateTo) + 1) / (1.0*DATEDIFF(minute, CAST(YEAR(@dateTo) AS CHAR(4))+'-01-01 00:00', CAST(YEAR(@dateTo) AS CHAR(4))+'-12-31 23:59') + 1)
答案 1 :(得分:0)
如果您想要准确性,可以在执行datediff
时花费几分钟并相应地相乘结果。您可以使用以下代码调整@dateFrom
和@dateTo
来测试输出:
DECLARE @dateFrom DATETIME, @dateTo DATETIME
SET @dateFrom = '2017-07-01 23:59'
SET @dateTo = '2017-07-02 00:01'
SELECT DATEDIFF(MINUTE, @dateFrom, @dateTo) minsDiff
SELECT DATEDIFF(MINUTE, @dateFrom, @dateTo) / 60.0 hoursDiff
SELECT DATEDIFF(MINUTE, @dateFrom, @dateTo) / 60.0 / 24.0 daysDiff
SELECT DATEDIFF(MINUTE, @dateFrom, @dateTo) / 60.0 / 24.0 / 365.25 yearsDiff
SELECT DATEDIFF(MINUTE, @dateFrom, @dateTo) / 60.0 / 24.0 / 365.25 * 12 monthsDiff
这完全取决于您要报告的内容以及您的业务逻辑。您可以执行其他类似的查询:
-- to track a change in days - take off the time portion:
SELECT DATEDIFF(DAY, CAST(@dateFrom AS DATE), CAST(@dateTo AS DATE)) daysDiff
-- to track a change in years - you use the year funtion:
SELECT YEAR(@dateTo) - YEAR(@dateFrom) yearsDiff