SQL中DATEDIFF计算DateTimeOffset返回错误值,问题出在哪?
解决SQL Server中DateTimeOffset计算天数差不符合预期的问题
我之前也踩过这个坑,咱们先来拆解下问题出在哪:
你执行的这段SQL代码:
DECLARE @timeInZone1 AS DATETIMEOFFSET DECLARE @timeInZone2 AS DATETIMEOFFSET SET @timeInZone1 = '2012-01-13 00:00:00 +1:00'; SET @timeInZone2 = '2012-01-13 23:00:00 +1:00'; SELECT DATEDIFF( day, @timeInZone1, @timeInZone2 );
预期返回0,但实际得到1,核心原因是SQL Server的DATEDIFF函数计算的是「时间边界的跨越次数」,而非实际的时间间隔时长。
为什么会这样?
DATEDIFF处理DATETIMEOFFSET类型时,会先把两个时间转换为UTC时间再计算:
@timeInZone1转换成UTC是2012-01-12 23:00:00@timeInZone2转换成UTC是2012-01-13 22:00:00
当指定day作为单位时,函数会统计两个时间之间UTC午夜0点的跨越次数——从12号23点到13号22点,刚好跨越了一次13号的午夜0点,所以返回1。
怎么得到预期的结果?
根据你的需求,有两种可行的解决方式:
1. 计算实际的24小时间隔天数
如果要按「满24小时算一天」的逻辑,用小时差除以24即可:
DECLARE @timeInZone1 AS DATETIMEOFFSET DECLARE @timeInZone2 AS DATETIMEOFFSET SET @timeInZone1 = '2012-01-13 00:00:00 +1:00'; SET @timeInZone2 = '2012-01-13 23:00:00 +1:00'; -- 得到精确的天数(带小数),如果要整数0可以用FLOOR或者CAST SELECT DATEDIFF(hour, @timeInZone1, @timeInZone2)/24.0 AS ActualDayDiff; -- 或者取整 SELECT FLOOR(DATEDIFF(hour, @timeInZone1, @timeInZone2)/24.0) AS IntegerDayDiff;
2. 基于本地时间的日期边界计算
如果你想以本地时间的日期(比如都是1月13号就算0天)为判断标准,先把DATETIMEOFFSET转换为本地DATETIME再计算:
DECLARE @timeInZone1 AS DATETIMEOFFSET DECLARE @timeInZone2 AS DATETIMEOFFSET SET @timeInZone1 = '2012-01-13 00:00:00 +1:00'; SET @timeInZone2 = '2012-01-13 23:00:00 +1:00'; SELECT DATEDIFF(day, CONVERT(DATETIME, @timeInZone1), CONVERT(DATETIME, @timeInZone2)) AS LocalDayDiff;
这段代码会返回你预期的0,因为转换后的本地时间都属于1月13号,没有跨越日期边界。
内容的提问来源于stack exchange,提问作者Osel Miko Dřevorubec
相关产品推荐
相关产品推荐

