我在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()
到BIGINT
或DECIMAL(13,0)
的任何变量我做了,导致了同样的错误。
此查询中哪个错误? int
的默认返回数据类型是DATEDIFF()
吗?
我知道我可以将@Time
除以1000并使用SECONDS
代替MILLISECONDS
,我只是想知道是否有办法直接以毫秒为单位,因为我们的想法是将此脚本用作内联表值函数(由于此查询之外的其他原因,不能使用标量函数)。
答案 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>)