将SQL Server DateTime对象转换为BIGINT(.Net ticks)

Lir*_*uda 15 .net sql sql-server

我需要将.Net ticks格式的DateTime类型值转换为BIGINT类型(自0001年1月1日午夜12:00:00起已经过的100纳秒间隔的数量).

应使用T-SQL查询在Sql server 2008中执行转换

例如:

DateTime value - 12/09/2011 00:00:00
Run Code Online (Sandbox Code Playgroud)

将转换为:

BIGINT value - 634513824000000000
Run Code Online (Sandbox Code Playgroud)

Jef*_*ata 21

我讨论是否发布这个因为它取决于SQL Server中二进制级别的日期存储方式,因此它是一个非常脆弱的解决方案.对于除了一次性转换之外的任何事情,我会使用类似@Solution Evangelist发布的答案.尽管如此,你可能会以学术的方式发现这有趣,所以无论如何我都会发布它.

利用DateTime2与.NET中的刻度持续时间匹配的准确性以及两者都基于开始日期的事实01-01-0001 00:00:00.0000000,您可以将其转换DateTime为to DateTime2,然后将其强制转换为binary(9):0x07F06C999F3CB7340B

日期时间信息存储在RTL中,所以反转,我们会得到0x0B34B73C9F996CF007.

前三个字节存储01-01-0001自那天起的天数,接下来的5个字节存储自当天午夜起的100ns刻度,因此我们可以将天数乘以一天中的刻度并添加表示经过的时间的刻度.那天.

执行以下代码:

set @date = getdate()
set @ticksPerDay = 864000000000

declare @date2 datetime2 = @date

declare @dateBinary binary(9) = cast(reverse(cast(@date2 as binary(9))) as binary(9))
declare @days bigint = cast(substring(@dateBinary, 1, 3) as bigint)
declare @time bigint = cast(substring(@dateBinary, 4, 5) as bigint)

select @date as [DateTime], @date2 as [DateTime2], @days * @ticksPerDay + @time as [Ticks]
Run Code Online (Sandbox Code Playgroud)

返回以下结果:

DateTime                DateTime2              Ticks
----------------------- ---------------------- --------------------
2011-09-12 07:20:32.587 2011-09-12 07:20:32.58 634514088325870000
Run Code Online (Sandbox Code Playgroud)

获取返回的Ticks数并转换回.NET中的DateTime:

DateTime dt = new DateTime(634514088325870000);
dt.ToString("yyyy-MM-dd HH:mm:ss.fffffff").Dump();
Run Code Online (Sandbox Code Playgroud)

从sql server返回日期:

2011-09-12 07:20:32.5870000


Aar*_*ron 17

我找到了一篇可能有帮助的CodeProject文章:使用T-SQL将DateTime转换为.NET Ticks

我附上上面文章中的SQL函数(我希望这样可以吗?因为它需要注册.)

CREATE FUNCTION [dbo].[MonthToDays365] (@month int)
RETURNS int
WITH SCHEMABINDING
AS
-- converts the given month (0-12) to the corresponding number of days into the year (by end of month)
-- this function is for non-leap years
BEGIN 
RETURN
    CASE @month
        WHEN 0 THEN 0
        WHEN 1 THEN 31
        WHEN 2 THEN 59
        WHEN 3 THEN 90
        WHEN 4 THEN 120
        WHEN 5 THEN 151
        WHEN 6 THEN 181
        WHEN 7 THEN 212
        WHEN 8 THEN 243
        WHEN 9 THEN 273
        WHEN 10 THEN 304
        WHEN 11 THEN 334
        WHEN 12 THEN 365
        ELSE 0
    END
END

GO

CREATE FUNCTION [dbo].[MonthToDays366] (@month int)
RETURNS int 
WITH SCHEMABINDING
AS
-- converts the given month (0-12) to the corresponding number of days into the year (by end of month)
-- this function is for leap years
BEGIN 
RETURN
    CASE @month
        WHEN 0 THEN 0
        WHEN 1 THEN 31
        WHEN 2 THEN 60
        WHEN 3 THEN 91
        WHEN 4 THEN 121
        WHEN 5 THEN 152
        WHEN 6 THEN 182
        WHEN 7 THEN 213
        WHEN 8 THEN 244
        WHEN 9 THEN 274
        WHEN 10 THEN 305
        WHEN 11 THEN 335
        WHEN 12 THEN 366
        ELSE 0
    END
END

GO

CREATE FUNCTION [dbo].[MonthToDays] (@year int, @month int)
RETURNS int
WITH SCHEMABINDING
AS
-- converts the given month (0-12) to the corresponding number of days into the year (by end of month)
-- this function is for non-leap years
BEGIN 
RETURN 
    -- determine whether the given year is a leap year
    CASE 
        WHEN (@year % 4 = 0) and ((@year % 100  != 0) or ((@year % 100 = 0) and (@year % 400 = 0))) THEN dbo.MonthToDays366(@month)
        ELSE dbo.MonthToDays365(@month)
    END
END

GO

CREATE FUNCTION [dbo].[TimeToTicks] (@hour int, @minute int, @second int)  
RETURNS bigint 
WITH SCHEMABINDING
AS 
-- converts the given hour/minute/second to the corresponding ticks
BEGIN 
RETURN (((@hour * 3600) + CONVERT(bigint, @minute) * 60) + CONVERT(bigint, @second)) * 10000000
END

GO

CREATE FUNCTION [dbo].[DateToTicks] (@year int, @month int, @day int)
RETURNS bigint
WITH SCHEMABINDING
AS
-- converts the given year/month/day to the corresponding ticks
BEGIN 
RETURN CONVERT(bigint, (((((((@year - 1) * 365) + ((@year - 1) / 4)) - ((@year - 1) / 100)) + ((@year - 1) / 400)) + dbo.MonthToDays(@year, @month - 1)) + @day) - 1) * 864000000000;
END

GO

CREATE FUNCTION [dbo].[DateTimeToTicks] (@d datetime)
RETURNS bigint
WITH SCHEMABINDING
AS
-- converts the given datetime to .NET-compatible ticks
-- see https://msdn.microsoft.com/en-us/library/system.datetime.ticks(v=vs.110).aspx
BEGIN 
RETURN 
    dbo.DateToTicks(DATEPART(yyyy, @d), DATEPART(mm, @d), DATEPART(dd, @d)) +
    dbo.TimeToTicks(DATEPART(hh, @d), DATEPART(mi, @d), DATEPART(ss, @d)) +
    (CONVERT(bigint, DATEPART(ms, @d)) * CONVERT(bigint,10000));
END

GO
Run Code Online (Sandbox Code Playgroud)


rob*_*rt4 5

我错过了这个问题的毫秒级精确的单行解决方案,所以这里是一个:

\n\n
SELECT ROUND(CAST(CAST(GETUTCDATE() AS FLOAT)*8.64e8 AS BIGINT),-1)*1000+599266080000000000\n
Run Code Online (Sandbox Code Playgroud)\n\n

8.64e8 = TimeSpan.TicksPerDay / 1000
\n599266080000000000 = DateTime.Parse('1900-01-01').Ticks

\n\n

这适用于 DATETIME 类型,但不适用于 DATETIME2。DATETIME 的 4/3 毫秒分辨率使得必须涉及 ROUND(\xe2\x80\xa6,-1):乘以 8.64e8 后,浮点结果始终以 0 或 33.3 或 66.6 结尾。该值四舍五入为 0、30 或 70。

\n