2010-02-22 51 views
10

Estoy guardando un valor de TimeSpan (de .NET) en mi db como BIGINT en SQL Server (guardando la propiedad Ticks). Quiero saber cómo convertir este valor BIGINT a un valor DATETIME en SQL Server (no en .NET). ¿Algunas ideas?Convertir .NET Ticks a SQL Server DateTime

Saludos

EDIT:

estoy usando NHibernate para asignar una propiedad TimeSpan que tengo, y que persiste la propiedad garrapatas. Lo uso durante horas relativas (o minutos) control sobre alguna fecha.

Internamente en el sistema todo está bien, esta conversión no es necesaria. Sin embargo, al realizar consultas aleatorias en SQL Server, es difícil comprender la forma persistente de TimeSpan. Entonces, una función donde paso el valor Ticks y se devuelve DateTime daría la cantidad en horas, minutos y segundos que representa TimeSpan.

Respuesta

17

no estoy seguro de cómo es exacto es que sea con los segundos, pero se puede intentar algo como:

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) 

realidad de otra manera que trabajaría en SQL 2005 es de hacer notar que el número de garrapatas de 0001-01-01 a 1900-01-01 es 599266080000000000.Con esto se podría hacer:

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') 
+0

concedido ... esto requiere SQL 2008 y su tipo de datos FECHA. – Thomas

+0

Por cierto, también debe tenerse en cuenta que el valor de Garrapatas comienza desde '0001-01-01' ** no ** '1900-01-01'. – Thomas

+0

El código es excelente, pero si el intervalo de tiempo representa horas solamente y no una fecha completa, la fecha resultante es demasiado baja para representarse como fecha y hora. Pero el código es un buen comienzo, lo marcaré como respuesta y trabajaré en ello. ¡Muchas gracias! – Pedro

6

A TimeSpan no es una fecha, y guardarla como tal puede causar confusión en el futuro.

¿Hay alguna razón por la que no pueda simplemente guardar los tics en un campo entero y no cambiar su significado?

+0

por favor, revise la pregunta actualizada – Pedro

2

Debería poder usar la función CAST integrada en SQL Server.

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

que presentamos lo mejor 2010-02-02 00: 00: 00.000

+2

Extrañamente pasando de tics y usando select (CAST (CAST (633979266000000000 AS BIGINT) como datetime)) da un error de desbordamiento aritmético. – Jafin

3

obtener el valor de TimeSpan.TicksPerSecond en .NET (solo escribirlo).

Luego, en su SQL, puede dividir el conteo de ticks por ese número, para dar la cantidad de segundos.

A continuación, puede dividir este por 60 minutos para llegar, etc.

1

que se ha dado cuenta en mis propias:

288,000,000,000 garrapatas representa 8 horas, por lo que el siguiente SELECT devuelve una fecha ficticia con el cantidad de horas especificada ...

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

Gracias a todos los esfuerzos.

8

Puede utilizar esta función tomado de Pavel Gatilov's blog para convertir un entero de 64 bits con un valor de fecha y hora con una precisión de milisegundos en el servidor local:

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 

código alternativo adecuado para el uso en línea:

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() 
+0

Tenga en cuenta que esta función puede devolver fechas de tiempo que difieren en unos pocos ms para el mismo valor de ticks de entrada. La declaración de devolución realiza dos llamadas distintas para obtener la fecha y hora actual, y el tiempo puede (algunas veces) transcurrir entre esas llamadas. –

+0

+1 para el bastante brillante UTC -> Conversión local. Hay artículo tras artículo en línea que le dice a la gente que cree tablas de compensación de zona horaria y cosas así, y luego está esto, tan simple y enterrado en un tema aparentemente no relacionado. –

+0

La conversión UTC -> local es útil solo si la fecha que está comparando es reciente. Si está usando una fecha que no está seguro si fue durante el horario de verano (horario de verano de A.K.A.), entonces aún necesita hacer algunas comparaciones para convertir correctamente. [Aquí hay un buen ejemplo para comenzar con eso] (http://www.mssqltips.com/sqlservertip/1372/daylight-savings-time-functions-in-sql-server/) – gooddadmike

7

que no se sabe muy bien de SQL Server, pero hoy en día un colega mío tuvo el mismo problema y yo creo he encontrado una solución como esta:

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

donde 599266080000000000 es el valor de garrapatas 01/01/1900 00:00:00.

+0

Esto es realmente una reiteración del respuestas anteriores, pero creo que tiene algún mérito porque me parece más simple. – fogbank

Cuestiones relacionadas