4

我需要在T-SQL SELECT 语句(在 SQL Server 2000 上)中将 SQL Server DATETIME值转换为 FILETIME 。是否有内置功能可以做到这一点?如果没有,有人可以帮我弄清楚如何将此转换例程实现为 UDF(或只是简单的 Transact-SQL)吗?这是我所知道的:

  1. FILETIME 是 64 位值,表示自 1601 年 1 月 1 日 (UTC) 以来的 100 纳秒间隔数(根据MSDN:FILETIME Structure)。
  2. SQL Server 基准时间从 1900-01-01 00:00:00 开始(每个 SELECT CAST(0 as DATETIME))。

我发现了几个示例,展示了如何将 FILETIME 值转换为 T-SQL DATETIME(不过,我不能 100% 确定它们是准确的),但找不到任何关于反向转换的信息。即使是一般的想法(或算法)也会有所帮助。

4

3 回答 3

4

好的,我想我能够自己实现这一点。这是功能:

IF EXISTS 
(
    SELECT 1
    FROM   sysobjects 
    WHERE  id   = OBJECT_ID('[dbo].[fnDateTimeToFileTime]')
      AND  type = 'FN'
)
BEGIN
    DROP FUNCTION [dbo].[fnDateTimeToFileTime]
END
GO

-- Create function.
CREATE FUNCTION [dbo].[fnDateTimeToFileTime]
(
    @DateTime AS DATETIME
)
RETURNS
    BIGINT
BEGIN

IF @DateTime IS NULL
    RETURN NULL

DECLARE @MsecBetween1601And1970 BIGINT
DECLARE @MsecBetween1970AndDate BIGINT

SET @MsecBetween1601And1970 = 11644473600000

SET @MsecBetween1970AndDate = 
    DATEDIFF(ss, CAST('1970-01-01 00:00:00' as DATETIME), @DateTime) * 
        CAST(1000 AS BIGINT)

RETURN (@MsecBetween1601And1970 + @MsecBetween1970AndDate) * CAST(10000 AS BIGINT)  
END
GO

IF @@ERROR = 0
    GRANT EXECUTE ON [dbo].[fnDateTimeToFileTime] TO Public 
GO

它似乎精确到 1 秒,这对我来说没问题(由于数据溢出,我无法使其更准确)。我使用TimeAndDate 网络工具来计算日期之间的持续时间。

你怎么看?

于 2010-06-01T18:03:06.210 回答
2

2 SQL Server 时间时代从 1900-01-01 00:00:00 开始(每个 SELECT CAST(0 作为 DATETIME)。

不,那是基准日期,日期时间从 1753 开始

运行这个

select cast('17800122' as datetime) 

输出

1780-01-22 00:00:00.000

但这仍然小于文件时间,因此您需要添加...但是请记住公历和儒略历(也是日期时间从 1753 开始的原因)

于 2010-05-27T19:27:39.803 回答
1

接受的答案效果很好,但会在 2038 年 1 月 19 日以上的日期崩溃。如果您使用的是 SQL Server 2016 或更高版本,请使用 DATEDIFF_BIG 而不是 DATEDIFF,或者使用以下更正

CREATE FUNCTION [dbo].[fnDateTimeToFileTime]
(
    @DateTime AS DATETIME
)
RETURNS
    BIGINT
BEGIN

IF @DateTime IS NULL
    RETURN NULL

DECLARE @MsecBetween1601And1970 BIGINT
DECLARE @MsecBetween1970AndDate BIGINT

DECLARE @MaxNumberDayBeforeOverflowDateDiff int;
SET @MaxNumberDayBeforeOverflowDateDiff  = 24855; --SELECT DATEDIFF(day, CAST('1970-01-01 00:00:00' as DATETIME), CAST('2038-01-19 00:00:00' as DATETIME))

DECLARE @nbMaxDaysBetween1970AndDate int;
SET @nbMaxDaysBetween1970AndDate = DATEDIFF(day, CAST('1970-01-01 00:00:00' as DATETIME), @DateTime) / @MaxNumberDayBeforeOverflowDateDiff;

DECLARE @moduloResteDay int
SET @moduloResteDay = DATEDIFF(day, CAST('1970-01-01 00:00:00' as DATETIME), @DateTime) % @MaxNumberDayBeforeOverflowDateDiff;

DECLARE @nbSecondBefore19700101And20380119 bigint = 2147472000;
SET @MsecBetween1601And1970 = 11644473600000;

DECLARE @DateTimeModulo datetime;
SET @DateTimeModulo = DATEADD(day, -@nbMaxDaysBetween1970AndDate * @MaxNumberDayBeforeOverflowDateDiff, @DateTime)


SET @MsecBetween1970AndDate = CAST(CAST(@nbMaxDaysBetween1970AndDate as bigint) * @nbSecondBefore19700101And20380119 + 
    DATEDIFF(ss, CAST('1970-01-01 00:00:00' as DATETIME), @DateTimeModulo) as bigint)* 
        CAST(1000 AS BIGINT)

RETURN (@MsecBetween1601And1970 + @MsecBetween1970AndDate) * CAST(10000 AS BIGINT) 
END
于 2020-10-26T15:10:28.693 回答