T-SQL - 使用毫秒时算术溢出

时间:2014-11-17 16:48:33

标签: sql sql-server sql-server-2008

我在TSQL中有一个非常简单的脚本尝试将时间戳(以毫秒为单位)转换为DATETIME数据类型。这还包括本地时间偏移。

DECLARE @Time AS BIGINT
SET @Time = 1413381394000 
SELECT DATEADD(MILLISECOND, 
               @Time - DATEDIFF(MILLISECOND, GETDATE(), GETUTCDATE()), CAST('1970-01-01 00:00:00' AS DATETIME)) AS [Datetime]

它一直给我的错误是:

Arithmetic overflow error converting expression to data type int.

现在,我在此查询中没有任何明确的 int变量,以及CAST()BIGINTDECIMAL(13,0)的任何变量我做了,导致了同样的错误。

此查询中哪个错误? int的默认返回数据类型是DATEDIFF()吗?

我知道我可以将@Time除以1000并使用SECONDS代替MILLISECONDS,我只是想知道是否有办法直接以毫秒为单位,因为我们的想法是将此脚本用作内联表值函数(由于此查询之外的其他原因,不能使用标量函数)。

3 个答案:

答案 0 :(得分:1)

DateDiff()确实会返回一个int,但我怀疑它是DateAdd()给你的错误信息。

不幸的是,正如你所说的那样,你需要以这种精确度工作,因为你想要在几毫秒内完成工作。

  

DATEADD(datepart,number,date)

     

number是一个表达式,可以解析为添加到date日期部分的int。用户定义的变量有效。

显然,您可以使用循环或其他东西对您进行编码,但显然您需要经历这样的成本/收益。

答案 1 :(得分:1)

由于夏令时,您对本地偏移的计算可能会错误一小时。 DATEDIFF(MILLISECOND, GETDATE(), GETUTCDATE())只会获取当前偏移量而不是给定日期的偏移量。由于SQL缺乏用于此目的的功能,因此通常最好在应用程序或SQLCLR代码中处理与UTC和本地时间之间的转换。请参阅How can I get the correct offset between UTC and local times for a date that is before or after DST?

DATEADD (Transact-SQL) Microsoft声明:

  


      是一个可以解析为添加的int的表达式       到日期的日期部分。用户定义的变量有效。

If you specify a value with a decimal fraction, the fraction is
truncated and not rounded.

因此,您不能直接使用大于int的最大值的毫秒值,该值支持范围为-2 ^ 31(-2,147,483,648)到2 ^ 31-1(2,147,483,647),如int, bigint, smallint, and tinyint (Transact-SQL)中所述。你必须做的是分开日期添加和一些模数除法。

DECLARE @Time bigint
DECLARE @Seconds int
DECLARE @RemainingMilliseconds int
DECLARE @EpochDate datetime

SET @Time = 1413381394000

SET @EpochDate = '1970-01-01 00:00:00'
SET @Seconds = @Time / 1000
SET @RemainingMilliseconds = @Time % 1000

SELECT DATEADD(MILLISECOND, @RemainingMilliseconds, DATEADD(SECOND,@Seconds, @EpochDate))

答案 2 :(得分:0)

DATEADD的第二个参数应该是INT而不是BIGINT。转换为秒,然后传递给日期添加。

DECLARE @Time AS BIGINT
SET @Time = 1413381394000 
DECLARE @seconds AS INT = @Time / 1000
SELECT DATEADD(SECOND, @seconds, ...)

如果您不想丢失毫秒,可以添加第二步:

DECLARE @milliseconds INT = @Time % 1000
SELECT DATEADD(MILLISECOND, @milliseconds, <date from before>)