Конвертировать отметки .NET в SQL Server DateTime - PullRequest
12 голосов
/ 22 февраля 2010

Я сохраняю значение TimeSpan (из .NET) в моей базе данных как BIGINT в SQL Server (сохраняя свойство Ticks). Я хочу знать, как преобразовать это BIGINT значение в DATETIME значение в SQL Server (не в .NET). Есть идеи?

Приветствия

EDIT:

Я использую NHibernate для сопоставления имеющегося у меня свойства TimeSpan, и оно сохраняется в свойстве Ticks. Я использую его для контроля относительных часов (или минут) какой-либо даты.

Внутри системы все нормально, это преобразование не нужно. Однако при выполнении случайных запросов в SQL Server трудно понять постоянную форму TimeSpan. Итак, функция, в которой я передаю значение Ticks и возвращается DateTime, выдаст сумму в часах, минутах и ​​секундах, которую представляет TimeSpan.

Ответы [ 7 ]

18 голосов
/ 22 февраля 2010

Я не уверен, насколько точно это будет с секундами, но вы можете попробовать что-то вроде:

Declare @TickValue bigint
Declare @Days float

Set @TickValue = 634024345696365272 
Select @Days = @TickValue * POWER(10.00000000000,-7) / 60 / 60 / 24

Select DATEADD(d, Cast(@Days As int), Cast('0001-01-01' As DATE)) 
    + Cast( (@Days - FLOOR(@Days)) As DateTime)

На самом деле еще один способ, который будет работать в SQL 2005, - это отметить, что число тактов с 0001-01-01 по 1900-01-01 составляет 599266080000000000. С этим вы можете сделать:

Declare @TickOf19000101 bigint
Declare @TickValue bigint
Declare @Minutes float

Set @TickOf19000101  = 599266080000000000
Set @TickValue = DATEDIFF(mi, 0 ,CURRENT_TIMESTAMP) * Cast(60 As BigInt) 
                   * POWER(10.00000000000,7) + @TickOf19000101

Select @TickValue
Select @Minutes = (@TickValue - @TickOf19000101) * POWER(10.00000000000,-7) / 60

Select @Minutes
Select DATEADD(MI, @Minutes, '1900-01-01')
14 голосов
/ 20 марта 2015

Я действительно не знаю SQL Server, но сегодня у моего коллеги возникла та же проблема, и я думаю Я нашел решение, подобное этому:

CAST(([ticks] - 599266080000000000) / 10000000 / 24 / 60 / 60 AS datetime)

, где 599266080000000000 - значение тиков на 01.01.1900 00: 00: 00.

8 голосов
/ 30 ноября 2012

Вы можете использовать эту функцию из блога Павла Гатилова для преобразования 64-разрядного целого числа в значение даты и времени с точностью до миллисекунды по местному времени сервера:

CREATE FUNCTION NetFxUtcTicksToDateTime
(
   @Ticks bigint
)
RETURNS datetime
AS
BEGIN

-- First, we will convert the ticks into a datetime value with UTC time
DECLARE @BaseDate datetime;
SET @BaseDate = '01/01/1900';

DECLARE @NetFxTicksFromBaseDate bigint;
SET @NetFxTicksFromBaseDate = @Ticks - 599266080000000000;
-- The numeric constant is the number of .Net Ticks between the System.DateTime.MinValue (01/01/0001) and the SQL Server datetime base date (01/01/1900)

DECLARE @DaysFromBaseDate int;
SET @DaysFromBaseDate = @NetFxTicksFromBaseDate / 864000000000;
-- The numeric constant is the number of .Net Ticks in a single day.

DECLARE @TimeOfDayInTicks bigint;
SET @TimeOfDayInTicks = @NetFxTicksFromBaseDate - @DaysFromBaseDate * 864000000000;

DECLARE @TimeOfDayInMilliseconds int;
SET @TimeOfDayInMilliseconds = @TimeOfDayInTicks / 10000;
-- A Tick equals to 100 nanoseconds which is 0.0001 milliseconds

DECLARE @UtcDate datetime;
SET @UtcDate = DATEADD(ms, @TimeOfDayInMilliseconds, DATEADD(d, @DaysFromBaseDate, @BaseDate));
-- The @UtcDate is already useful. If you need the time in UTC, just return this value.

-- Now, some magic to get the local time
RETURN @UtcDate + GETDATE() - GETUTCDATE();
END
GO

Альтернативный код, подходящий для встроенного использования:

DECLARE @Ticks bigint
set @Ticks = 634899090000000000
select DATEADD(ms, ((@Ticks - 599266080000000000) - 
   FLOOR((@Ticks - 599266080000000000) / 864000000000) * 864000000000) / 10000,
   DATEADD(d, (@Ticks - 599266080000000000) / 864000000000, '01/01/1900')) +
   GETDATE() - GETUTCDATE()
6 голосов
/ 22 февраля 2010

A TimeSpan не является датой, и сохранение ее как таковой может привести к путанице в будущем.

Есть ли причина, по которой вы не можете просто сохранить галочки в целочисленном поле и не изменить его значение?

3 голосов
/ 22 февраля 2010

Получить значение TimeSpan.TicksPerSecond в .NET (просто запишите его).

Затем в вашем SQL вы можете разделить количество тиков на это число, чтобы получить количество секунд.

Затем вы можете разделить это на 60, чтобы получить минуты и т. Д.

2 голосов
/ 22 февраля 2010

Вы должны быть в состоянии использовать функцию CAST , встроенную в SQL Server.

SELECT(CAST(CAST(CAST ('02/02/10' AS datetime) AS BIGINT) AS datetime)) 

Вы получаете 2010-02-02 00: 00: 00.000

1 голос
/ 22 февраля 2010

Я понял это самостоятельно:

288 000 000 000 тиков соответствует 8 часам, поэтому следующий SELECT возвращает фиктивную дату с указанным количеством часов ...

SELECT DATEADD(millisecond, 288000000000/10000, CAST('1900-01-01' AS DATETIME))

Благодаря всяким усилиям.

...