SQL 服务器 - 奇怪的 DateDiff 行为

SQL Sever - Weird DateDiff Behavior

我有以下简单查询

select DATEADD(MONTH, DATEDIFF(MONTH, -32, '2020-02-29')-32, -1)
select DATEADD(MONTH, DATEDIFF(MONTH, -31, '2020-02-29')-31, -1)

由于 -31 和 -32 中的月数不同,我预计每行的输出会有所不同。

这两行 return 2017-07-31 00:00:00.000 我完全不知道为什么!

有人可以给我解释一下吗?

documentation 中所述 dateadd():

If the following are true:

  • datepart is month
  • the date month has more days than the return month
  • the date day does not exist in the return month

Then, DATEADD returns the last day of the return month.

来自我的评论:

Why would you expect different values? Both DATEDIFF(MONTH, -32, '20200229')-32 and DATEDIFF(MONTH, -31, '20200229')-31 result in the value 1411. The "date" -1 is 1899-12-31, and adding 1411 months (117 years 7 months) to that is 2017-07-31.

让我们分解一下:

SELECT DATEDIFF(MONTH, -32, '20200229')-32 AS DD1, DATEDIFF(MONTH, -31, '20200229')-31 AS DD2;

这个 returns 以下:

DD1         DD2
----------- -----------
1411        1411

我们也可以将上面的步骤分解成更多的步骤。对于 datetime,日期 01900-01-01,每个完整整数表示在该日期上添加那么多天。 -32 作为日期因此是 1899-11-30,而 -311899-12-01。这给了我们以下 2 个表达式:

SELECT DATEDIFF(MONTH, '18991130', '20200229') AS M1, DATEDIFF(MONTH, '18991201', '20200229') AS M2;

这个 returns 以下:

M1          M2
----------- -----------
1443        1442

这是有道理的,因为 DATEDIFF 计算了 2 个日期之间 "ticks" 的次数。所以对于表达式 DATEDIFF(YEAR, '2019-12-31T23:59:59.9999999','2020-01-01T00:00:00.000000') 返回值 1,即使只过去了 1 毫秒,因为年份的值已经改变(1)。

该表达式的下一部分分别是 1443 - 321442 - 31。两者都是 1411(基础数学)。

然后你就有了 "date" -1。然后您将 1411 个月(即 117 年零 7 个月)添加到日期 1899-12-31,这(不出所料)returns 相同的值:2017-07-311899 + 117 = 201612 + 7 = 7因为我们是按月工作,所以把1转为年份:2017-07-31