2010-02-22 5 views
10

Je sauvegarde une valeur TimeSpan (à partir de .NET) dans ma base de données en tant que BIGINT dans SQL Server (en enregistrant la propriété Ticks). Je veux savoir comment convertir cette valeur BIGINT en valeur DATETIME dans SQL Server (pas dans .NET). Des idées?Convertir des tics .NET en SQL Server DateTime

Vive

EDIT:

J'utilise NHibernate pour mapper une propriété TimeSpan je, et il persiste la propriété Tiques. Je l'utilise pour le contrôle relatif des heures (ou des minutes) sur une date donnée.

En interne dans le système tout va bien, cette conversion n'est pas nécessaire. Toutefois, lors de l'exécution de requêtes aléatoires dans SQL Server, il est difficile de comprendre la forme persistante d'un TimeSpan. Donc, une fonction où je passe la valeur Ticks et un DateTime est retourné donnerait la quantité en heures, minutes et secondes que représente TimeSpan.

Répondre

17

Je ne sais pas comment ce sera précis avec les secondes, mais vous pouvez essayer quelque chose comme:

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) 

En fait, une autre façon qui fonctionnerait dans SQL 2005 est de noter que le nombre de tiques de 0001-01-01 à 1900-01-01 est 599266080000000000.Avec ce que vous pouvez faire:

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

Accordé .. nécessite SQL 2008 et son type de données DATE. – Thomas

+0

Btw, il convient également de noter que la valeur Ticks commence à partir de '0001-01-01' ** pas ** '1900-01-01'. – Thomas

+0

Le code est excellent, mais si le laps de temps représente uniquement des heures et non une date complète, la date résultante est trop faible pour être représentée comme une date/heure. Mais le code est un bon début, je vais le marquer comme réponse et travailler dessus. Merci beaucoup! – Pedro

6

Un TimeSpan n'est pas une date, et l'enregistrer en tant que tel peut causer de la confusion dans le futur.

Y a-t-il une raison pour laquelle vous ne pouvez pas simplement enregistrer les graduations dans un champ entier et ne pas en changer la signification?

+0

S'il vous plaît, vérifiez la question mise à jour – Pedro

2

Vous devriez pouvoir utiliser la fonction CAST intégrée à SQL Server.

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

vous obtenez 2010-02-02 00: 00: 00.000

+2

Étrangement allant de ticks et en utilisant select (CAST (CAST (633979266000000000 AS BIGINT) comme date/heure)) donne une erreur de débordement arithmétique. – Jafin

3

obtenir la valeur de TimeSpan.TicksPerSecond dans .NET (juste l'écrire).

Ensuite, dans votre SQL, vous pouvez diviser le nombre de ticks par ce nombre, pour donner le nombre de secondes.

Vous pouvez ensuite diviser par 60 pour obtenir des minutes, etc.

1

J'avoir compris cela sur mes propres:

288,000,000,000 tiques représente 8 heures, de sorte que le SELECT suivant retourne une date fictive avec le nombre d'heures spécifié ...

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

Merci à tous les efforts.

8

Vous pouvez utiliser cette fonction prise de Pavel Gatilov's blog pour convertir un entier de 64 bits à une valeur datetime avec une précision milliseconde à l'heure locale du serveur:

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 

code alternatif approprié pour une utilisation en ligne:

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

Attention, cette fonction peut retourner des dates qui diffèrent de quelques ms pour la même valeur de ticks d'entrée. L'instruction return fait deux appels distincts pour obtenir le datetime actuel, et le temps peut (parfois) passer entre ces appels. –

+0

+1 pour l'UTC plutôt brillant -> Conversion locale. Il ya article après article en ligne disant aux gens de créer des tableaux de décalage de fuseau horaire et autres, et puis il y a cela, si simple et enfoui dans un sujet apparemment sans rapport. –

+0

La conversion UTC -> locale n'est utile que si la date que vous comparez est récente. Si vous utilisez une date que vous n'êtes pas sûr si elle était pendant l'heure d'été (A.K.A. heure d'été) alors vous devez toujours faire quelques comparaisons pour convertir correctement. [Voici un bon exemple pour commencer avec cela] (http://www.mssqltips.com/sqlservertip/1372/daylight-savings-time-functions-in-sql-server/) – gooddadmike

7

Je ne sais pas vraiment SQL Server, mais aujourd'hui un de mes collègues a eu le même problème et je pense J'ai trouvé une solution comme ceci:

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

où 599266080000000000 est la valeur pour les tiques 01/01/1900 00:00:00.

+0

Ceci est vraiment une réitération de la réponses précédentes, mais je pense que cela a du mérite parce que cela me semble plus simple. – fogbank

Questions connexes