2010-02-22 7 views
10

Zapisuję wartość TimeSpan (z .NET) w moim db jako BIGINT w SQL Server (zapisanie właściwości Ticks). Chcę wiedzieć, jak przekonwertować wartość BIGINT na wartość DATETIME w SQL Server (nie w .NET). Jakieś pomysły?Konwersja .NET do SQL Server DataTime

Cheers

EDIT:

Używam NHibernate mapować TimeSpan właściwość mam, i utrzymuje właściwość kleszcze. Używam go do względnego kontrolowania godzin (lub minut) w pewnym terminie.

Wewnętrznie w systemie wszystko jest w porządku, ta konwersja nie jest potrzebna. Jednak podczas wykonywania losowych zapytań w SQL Serverze trudno jest zrozumieć utrwaloną formę TimeSpan. Tak więc funkcja, w której zwracam wartość Ticks i zwracana wartość DateTime, podałaby ilość w godzinach, minutach i sekundach, którą reprezentuje TimeSpan.

Odpowiedz

17

Nie jestem pewien, jak dokładne to będzie z sekund, ale można spróbować czegoś takiego:

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) 

Właściwie kolejny sposób, że będzie działać w SQL 2005 jest, aby pamiętać, że liczba kleszczy od 0001-01-01 do 1900-01-01 wynosi 599266080000000000.Z tym można zrobić:

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

Udzielone .. wymaga SQL 2008 i jego typ danych DATE. – Thomas

+0

Przy okazji należy również zauważyć, że wartość końcówek rozpoczyna się od "0001-01-01" ** nie ** '1900-01-01'. – Thomas

+0

Kod jest świetny, ale jeśli przedział czasowy reprezentuje tylko godziny, a nie pełną datę, wynikowa data jest zbyt niska, aby mogła być reprezentowana jako datetime. Ale kod jest dobrym początkiem, oznaczę to jako odpowiedź i nad nim pracuję. Dziękuję Ci bardzo! – Pedro

6

A TimeSpan nie jest datą, a jego zapisanie może spowodować zamieszanie w przyszłości.

Czy istnieje powód, dla którego nie można po prostu zapisać zaznaczeń w polu liczby całkowitej i nie zmienić jego znaczenia?

+0

proszę sprawdzić zaktualizowane pytanie – Pedro

2

Powinieneś być w stanie użyć funkcji CAST wbudowanej w SQL Server.

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

dostać 2010-02-02 00: 00: 00,000

+2

Dziwnie od ticks i przy użyciu select (CAST (CAST (633979266000000000 AS BIGINT) jako datetime)) daje błąd przepełnienia arytmetycznego. – Jafin

3

uzyskać wartość TimeSpan.TicksPerSecond w .NET (wystarczy napisać go w dół).

Następnie, w twoim SQL, możesz podzielić liczbę znaczników przez tę liczbę, aby podać liczbę sekund.

Można podzielić to przez 60 minut, aby dostać itp

1

mam zorientowaliśmy się na własnych:

288,000,000,000 kleszczy reprezentuje 8 godzin, więc po SELECT zwraca datę z manekina podana liczba godzin ...

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

Dzięki staraniom każdego użytkownika.

8

Można użyć tej funkcji zaczerpnięty z Pavel Gatilov's blog przekonwertować 64-bitową liczbę całkowitą do wartości datetime z dokładnością do milisekundy w serwerze Czas lokalny:

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 

kodu Alternatywnym odpowiednim dla inline użycia:

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

Należy pamiętać, że funkcja ta może zwrócić czasy pamięci, które różnią się o kilka ms od tej samej wartości znaczników wejściowych. Instrukcja return wykonuje dwa różne wywołania, aby uzyskać bieżącą datę i czas (czasami) może zostać przeniesiony pomiędzy tymi wywołaniami. –

+0

+1 za dość genialny UTC -> Lokalna konwersja. Jest artykuł po artykule, który mówi ludziom, jak tworzyć tabele z przesunięciem stref czasowych i takie tam, a potem jest tak prosty i pochowany w pozornie niezwiązanym temacie. –

+0

Konwersja UTC -> lokalna jest przydatna tylko wtedy, gdy porównywana data jest ostatnia. Jeśli używasz daty, w której nie masz pewności, czy było to podczas letniej oszczędności czasu letniego (A.K.A.), musisz wykonać kilka porównań, aby prawidłowo przeprowadzić konwersję. [Oto dobry przykład na początek] (http://www.mssqltips.com/sqlservertip/1372/daylight-savings-time-functions-in-sql-server/) – gooddadmike

7

ja naprawdę nie wiem, SQL Server, ale dzisiaj kolega miał ten sam problem i myślę Znalazłem rozwiązanie tak:

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

gdzie 599266080000000000 jest ticks wartość dla 01/01/1900 00:00:00.

+0

To jest naprawdę powtórzenie poprzednie odpowiedzi, ale myślę, że ma pewne zalety, ponieważ wydaje mi się prostsze. – fogbank