Jaki jest prawidłowy typ SQL do przechowywania przedziału czasu .Net o wartości> 24:00:00?

196

Usiłuję przechowywać .Net TimeSpanw SQL Server 2008 R2.

Najpierw wydaje się, że kod EF sugeruje, że powinien być przechowywany jako Time(7)SQL.

Jednak TimeSpanw .Net może obsługiwać okresy dłuższe niż 24 godziny.

Jaki jest najlepszy sposób na przechowywanie .Net TimeSpanw SQL Server?

GraemeMiller
źródło
15
Używam go do przechowywania długości powtarzających się zdarzeń. Dlatego chciałem uchwycić długość wydarzenia niezależnie od daty
GraemeMiller,
1
Powiązane nie są duplikaty. Napisałem je oba. Jeden dotyczy Code First i jak zmienić mapę dla TimeSpan. Drugi dotyczy rzeczywistego mapowania przedziału czasu na typ SQL. SQL.
GraemeMiller

Odpowiedzi:

222

Zapisałbym go w bazie danych jako BIGINTi zapisałbym liczbę znaczników (np. Właściwość TimeSpan.Ticks ).

W ten sposób, gdybym chciał uzyskać obiekt TimeSpan podczas jego odzyskiwania, mógłbym po prostu zrobić TimeSpan.FromTicks (wartość), co byłoby łatwe.

Tom Chantler
źródło
3
Jak poradziłbyś sobie z obliczeniami w sql, powiedzmy, że musisz obliczyć, ile godzin zawiera?
Peter
10
I prawdopodobnie przekształcić kleszczy do obiektu w czasie takiego: SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME). '1900-01-01'Data nie ma znaczenia, oczywiście, że to właśnie trzecia zmienna wymagane przez DATEADD(...)funkcję. Pamiętaj, że w kleszczu znajduje się 100 nanosekund, ale jeśli go użyjesz DATEADD(NANOSECOND..., prawdopodobnie wystąpi przepełnienie, dlatego używasz milisekund. Pamiętaj również, że powinieneś sprawdzić ten fakt za pomocą C # TimeSpan.TicksPerMillisecond(powinno być 10000), aby się upewnić.
Tom Chantler,
Opcją jest zapisanie go jako ciąg, a następnie można go załadować za pomocą TimeSpan.Parse (tekst). nie jest idealny z punktu widzenia wielkości lub zapytań SQL, ale w razie potrzeby można go analizować w języku TSQL
Walter Vehoeven
65

Dzięki za radę. Ponieważ nie ma odpowiednika w serwerze SQL. Po prostu utworzyłem drugie pole, które przekształciło TimeSpan w tiki i zapisało je w DB. Następnie uniemożliwiłem przechowywanie TimeSpan

public Int64 ValidityPeriodTicks { get; set; }

[NotMapped]
public TimeSpan ValidityPeriod
{
    get { return TimeSpan.FromTicks(ValidityPeriodTicks); }
    set { ValidityPeriodTicks = value.Ticks; }
}
GraemeMiller
źródło
6
Również dla każdego, kto korzysta z EF Core - w 2.1 możesz użyć konwersji wartości i TimeSpanToTicksConverter do przejrzystego mapowania przedziałów
czasowych do tyknięć
30

Jeśli nie musisz przechowywać więcej niż 24 godziny, możesz po prostu zapisać czas , ponieważ SQL Server 2008 i nowsze wersje są mapowane

time (SQL Server) <-> TimeSpan(.NET)

Nie potrzebujesz żadnych konwersji, jeśli potrzebujesz przechowywać tylko 24 godziny.

Źródło: http://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx

Ale jeśli chcesz przechowywać więcej niż 24 godziny, musisz przechowywać je w tikach, pobierać dane, a następnie konwertować na TimeSpan. Na przykład

int timeData = yourContext.yourTable.FirstOrDefault();
TimeSpan ts = TimeSpan.FromMilliseconds(timeData);
Alejandro del Río
źródło
23
Jak mówi OP, „czas” DataType w SQL Server obsługuje tylko do 24 godzin, chce przechowywać> 24h
MichelZ
11
TimeSpan (.NET) może być ujemny, a Time (SQL Server) nie.
Edward
11
Istnieje duża różnica między czasem a czasem trwania. Czas reprezentuje czas w danym dniu, podczas gdy czas trwania jest różnicą między dwiema chwilami. Porównaj to z lokalizacją (czas) i odległością (czas trwania).
Ramon de Klein
3
^ Dokładnie. - Typ SQL Timenie ma reprezentować czasu trwania, ale część Time wartości DateTime; to okropny wybór TimeSpan.
BrainSlugs83
19

Nie ma bezpośredniego odpowiednika. Po prostu przechowuj go numerycznie, np. Liczbę sekund lub coś odpowiedniego do wymaganej dokładności.

Strachofawhackplanet
źródło
to znaczy. zapisz go jako liczbę zmiennoprzecinkową i użyj `TimeSpan.FromSeconds` zgodnie z msdn.microsoft.com/en-us/library/…
CAD bloke
7

Wiem, że to stare pytanie, ale chciałem się upewnić, że odnotowano kilka innych opcji.

Ponieważ nie można przechowywać przedziału czasu większego niż 24 godziny w polu typu danych sql; może być kilka innych opcji.

  1. Użyj varchar (xx) do przechowywania ToString TimeSpan. Zaletą tego jest to, że precyzja nie musi być zapisywana w typie danych ani w obliczeniach (sekundy vs milisekundy vs dni vs dwa tygodnie) Wystarczy użyć TimeSpan.Parse / TryParse. Tak bym zrobił.

  2. Użyj drugiej daty, datetime lub datetimeoffset, która przechowuje wynik pierwszej daty + przedział czasu. Odczytywanie z db jest kwestią TimeSpan x = SecondDate - FirstDate. Użycie tej opcji ochroni Cię przed innymi bibliotekami dostępu do danych spoza platformy .NET, które mają dostęp do tych samych danych, ale nie rozumieją TimeSpans; jeśli masz takie środowisko.

stóg
źródło
1
Opcja 2 brzmi, jakby od czasu do czasu się przydała. thx
rahicks
3

Aby zachować spójność z prawdopodobnie najbardziej prawdopodobnym źródłem generowania przedziału czasu (obliczanie różnicy 2 razy lub daty i godziny), możesz przechowywać .NET TimeSpanjako DateTimetyp SQL Server .

Jest tak, ponieważ w programie SQL Server różnica 2 DateTime( Castdo Float, a następnie z Castpowrotem do a DateTime) jest po prostu DateTimewzględna w stosunku do 1 stycznia 1900 r. Np. Różnica wynosząca +0,1 sekundy to 1 stycznia 1900 00: 00: 00.100, a -0,1 sekundy to 31 grudnia 1899 23: 59: 59.900.

Aby przekonwertować platformę .NET TimeSpanna DateTimetyp programu SQL Server , należy najpierw przekonwertować ją na DateTimetyp .NET , dodając ją do wersji DateTimez 1 stycznia 1900 r. Oczywiście po przeczytaniu jej .NET z programu SQL Server najpierw przeczytaj go w .NET, DateTimea następnie odejmij od niego 1 stycznia 1900 r., aby przekonwertować go na .NET TimeSpan.

W przypadkach użycia, w których przedziały czasowe są generowane z SQL Server DateTimei SQL Server (tj. Przez T-SQL), a SQL Server jest wcześniejszy niż 2016, w zależności od zakresu i potrzeb w zakresie precyzji, przechowywanie ich może nie być praktyczne jako milisekundy (nie wspominając o tym Ticks), ponieważ Inttyp zwracany przez DateDiff(w porównaniu BigIntz SS 2016+ DateDiff_Big) przepełnia się po ~ 24 dniach wartości milisekund i ~ 67 lat. sekund. Rozwiązanie to poradzi sobie z przedziałami czasu z dokładnością do 0,1 sekundy i od -147 do +8,099 lat.

OSTRZEŻENIA:

  1. Działałoby to tylko wtedy, gdy różnica w stosunku do 1 stycznia 1900 r. DateTimeDałaby wartość w zakresie typu SQL Server (od 1 stycznia 1753 r. Do 31 grudnia 9999 r., Aka -147 do +0899 lat). Nie musimy się tak bardzo martwić po TimeSpanstronie .NET , ponieważ może pomieścić ~ 29 tys. Do +29 tys. Lat. Nie wspomniałem o DateTime2typie serwera SQL (którego zakres, po ujemnej stronie, jest znacznie większy niż SQL Server DateTime), ponieważ: a) nie można go przekonwertować na liczbę za pomocą prostej, Casta b) DateTimezakres powinien wystarczyć dla zdecydowanej większości przypadków użycia.

  2. SQL Server DateTimeróżnice obliczone za pośrednictwem Cast- do - Float- i - metoda z powrotem nie wydaje się być dokładne niż 0,1 sekundy.

Tomek
źródło
Zapomniałem, że nawet przeczytałem to Q, tym mniej, że napisałem to A, i ponownie szukałem A. Zacząłem czytać to A i pomyślałem sobie: (Wow, to najlepsza jak dotąd odpowiedź!). : D
Tom
3

Istnieje wiele sposobów prezentacji przedziału czasu w bazie danych.

czas

Ten typ danych jest obsługiwany od SQL Server 2008 i jest preferowanym sposobem przechowywania TimeSpan. Nie jest wymagane mapowanie. Działa również dobrze z kodem SQL.

public TimeSpan ValidityPeriod { get; set; }

Jednak, jak stwierdzono w pierwotnym pytaniu, ten typ danych jest ograniczony do 24 godzin.

datetimeoffset

Typ datetimeoffsetdanych jest mapowany bezpośrednio na System.DateTimeOffset. Służy do wyrażenia przesunięcia między a datetime/ datetime2UTC, ale możesz go również użyć do TimeSpan.

Ponieważ jednak typ danych sugeruje bardzo specyficzny semantyczny, należy również rozważyć inne opcje.

datetime / datetime2

Jednym z podejść może być użycie datetimelubdatetime2 typów . Jest to najlepsze w scenariuszach, w których trzeba bezpośrednio przetwarzać wartości w bazie danych, tj. dla widoków, procedur przechowywanych lub raportów. Wadą jest to, że musisz odjąć wartość DateTime(1900,01,01,00,00,00)od daty, aby odzyskać czas w logice biznesowej.

public DateTime ValidityPeriod { get; set; }

[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
    get { return ValidityPeriod - DateTime(1900,01,01,00,00,00); }
    set { ValidityPeriod = DateTime(1900,01,01,00,00,00) + value; }
}

bigint

Innym podejściem może być konwersja TimeSpan na tiki i użycie bigint typu danych. Jednak takie podejście ma tę wadę, że uciążliwe jest stosowanie go w zapytaniach SQL.

public long ValidityPeriod { get; set; }

[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
    get { return TimeSpan.FromTicks(ValidityPeriod); }
    set { ValidityPeriod = value.Ticks; }
}

Varchar (N)

Jest to najlepsze w przypadkach, w których wartość powinna być czytelna dla ludzi. Możesz również użyć tego formatu w zapytaniach SQL, korzystając z CONVERT(datetime, ValidityPeriod)funkcji. W zależności od wymaganej precyzji potrzebujesz od 8 do 25 znaków.

public string ValidityPeriod { get; set; }

[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
    get { return TimeSpan.Parse(ValidityPeriod); }
    set { ValidityPeriod = value.ToString("HH:mm:ss"); }
}

Bonus: okres i czas trwania

Za pomocą ciągu możesz także przechowywać typy danych NodaTime , zwłaszcza DurationiPeriod . Pierwszy jest zasadniczo taki sam jak TimeSpan, natomiast później uwzględnia, że ​​niektóre dni i miesiące są dłuższe lub krótsze niż inne (tj. Styczeń ma 31 dni, a luty 28 lub 29; niektóre dni są dłuższe lub krótsze z powodu czasu letniego ). W takich przypadkach użycie TimeSpan jest złym wyborem.

Możesz użyć tego kodu do konwersji okresów:

using NodaTime;
using NodaTime.Serialization.JsonNet;

internal static class PeriodExtensions
{
    public static Period ToPeriod(this string input)
    {
        var js = JsonSerializer.Create(new JsonSerializerSettings());
        js.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
        var quoted = string.Concat(@"""", input, @"""");
        return js.Deserialize<Period>(new JsonTextReader(new StringReader(quoted)));
    }
}

A potem użyj go jak

public string ValidityPeriod { get; set; }

[NotMapped]
public Period ValidityPeriodPeriod
{
    get => ValidityPeriod.ToPeriod();
    set => ValidityPeriod = value.ToString();
}

naprawdę lubię NodaTime i często ratuje mnie przed trudnymi błędami i dużym bólem głowy. Wadą tego rozwiązania jest to, że tak naprawdę nie można go używać w zapytaniach SQL i trzeba wykonywać obliczenia w pamięci.

Typ zdefiniowany przez użytkownika CLR

Możesz także użyć niestandardowego typu danych i bezpośrednio obsługiwać niestandardową TimeSpanklasę. Aby uzyskać szczegółowe informacje, zobacz Typy zdefiniowane przez użytkownika CLR .

Wadą jest to, że typ danych może nie zachowywać się dobrze w przypadku raportów SQL. Ponadto niektóre wersje programu SQL Server (Azure, Linux, Data Warehouse) nie są obsługiwane.

Konwersje wartości

Począwszy od EntityFramework Core 2.1, masz możliwość użycia konwersji wartości .

Jednak podczas korzystania z tego EF nie będzie w stanie przekonwertować wielu zapytań na SQL, co spowoduje, że zapytania będą działać w pamięci; potencjalnie przesyłając wiele danych do aplikacji.

Przynajmniej na razie lepiej nie używać go i po prostu zmapować wynik zapytania za pomocą Automappera .

MovGP0
źródło
1

Zazwyczaj przechowuję TimeSpan jako bigint wypełniony kleszczami z właściwości TimeSpan.Ticks, jak wcześniej sugerowano. Możesz także zapisać TimeSpan jako varchar (26) wypełniony danymi wyjściowymi TimeSpan.ToString (). Cztery funkcje skalarne (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks), które napisałem, są pomocne w obsłudze TimeSpan po stronie SQL i unikają włamań, które spowodowałyby sztucznie ograniczone zakresy. Jeśli możesz przechowywać interwał w .NET TimeSpan, powinien on także działać z tymi funkcjami. Ponadto funkcje pozwalają na pracę z TimeSpans i 100-nanosekundowymi taktami, nawet przy użyciu technologii, które nie obejmują .NET Framework.

DROP FUNCTION [dbo].[DateDiffTicks]
GO

DROP FUNCTION [dbo].[DateAddTicks]
GO

DROP FUNCTION [dbo].[ConvertToTimeSpanString]
GO

DROP FUNCTION [dbo].[ConvertFromTimeSpanString]
GO

SET ANSI_NULLS OFF
GO

SET QUOTED_IDENTIFIER OFF
GO

-- =============================================
-- Author:      James Coe
-- Create date: 2011-05-23
-- Description: Converts from a varchar(26) TimeSpan string to a bigint containing the number of 100 nanosecond ticks.
-- =============================================
/*
    [-][d.]hh:mm:ss[.fffffff] 

    "-" 
     A minus sign, which indicates a negative time interval. No sign is included for a positive time span.

    "d" 
     The number of days in the time interval. This element is omitted if the time interval is less than one day. 

    "hh" 
     The number of hours in the time interval, ranging from 0 to 23. 

    "mm" 
     The number of minutes in the time interval, ranging from 0 to 59. 

    "ss" 
     The number of seconds in the time interval, ranging from 0 to 59. 

    "fffffff" 
     Fractional seconds in the time interval. This element is omitted if the time interval does not include 
     fractional seconds. If present, fractional seconds are always expressed using seven decimal digits.
    */
CREATE FUNCTION [dbo].[ConvertFromTimeSpanString] (@timeSpan varchar(26))
RETURNS bigint
AS
BEGIN
    DECLARE @hourStart int
    DECLARE @minuteStart int
    DECLARE @secondStart int
    DECLARE @ticks bigint
    DECLARE @hours bigint
    DECLARE @minutes bigint
    DECLARE @seconds DECIMAL(9, 7)

    SET @hourStart = CHARINDEX('.', @timeSpan) + 1
    SET @minuteStart = CHARINDEX(':', @timeSpan) + 1
    SET @secondStart = CHARINDEX(':', @timespan, @minuteStart) + 1
    SET @ticks = 0

    IF (@hourStart > 1 AND @hourStart < @minuteStart)
    BEGIN
        SET @ticks = CONVERT(bigint, LEFT(@timespan, @hourstart - 2)) * 864000000000
    END
    ELSE
    BEGIN
        SET @hourStart = 1
    END

    SET @hours = CONVERT(bigint, SUBSTRING(@timespan, @hourStart, @minuteStart - @hourStart - 1))
    SET @minutes = CONVERT(bigint, SUBSTRING(@timespan, @minuteStart, @secondStart - @minuteStart - 1))
    SET @seconds = CONVERT(DECIMAL(9, 7), SUBSTRING(@timespan, @secondStart, LEN(@timeSpan) - @secondStart + 1))

    IF (@ticks < 0)
    BEGIN
        SET @ticks = @ticks - @hours * 36000000000
    END
    ELSE
    BEGIN
        SET @ticks = @ticks + @hours * 36000000000
    END

    IF (@ticks < 0)
    BEGIN
        SET @ticks = @ticks - @minutes * 600000000
    END
    ELSE
    BEGIN
        SET @ticks = @ticks + @minutes * 600000000
    END

    IF (@ticks < 0)
    BEGIN
        SET @ticks = @ticks - @seconds * 10000000.0
    END
    ELSE
    BEGIN
        SET @ticks = @ticks + @seconds * 10000000.0
    END

    RETURN @ticks
END
GO

-- =============================================
-- Author:      James Coe
-- Create date: 2011-05-23
-- Description: Converts from a bigint containing the number of 100 nanosecond ticks to a varchar(26) TimeSpan string.
-- =============================================
/*
[-][d.]hh:mm:ss[.fffffff] 

"-" 
 A minus sign, which indicates a negative time interval. No sign is included for a positive time span.

"d" 
 The number of days in the time interval. This element is omitted if the time interval is less than one day. 

"hh" 
 The number of hours in the time interval, ranging from 0 to 23. 

"mm" 
 The number of minutes in the time interval, ranging from 0 to 59. 

"ss" 
 The number of seconds in the time interval, ranging from 0 to 59. 

"fffffff" 
 Fractional seconds in the time interval. This element is omitted if the time interval does not include 
 fractional seconds. If present, fractional seconds are always expressed using seven decimal digits.
*/
CREATE FUNCTION [dbo].[ConvertToTimeSpanString] (@ticks bigint)
RETURNS varchar(26)
AS
BEGIN
    DECLARE @timeSpanString varchar(26)

    IF (@ticks < 0)
    BEGIN
        SET @timeSpanString = '-'
    END
    ELSE
    BEGIN
        SET @timeSpanString = ''
    END

    -- Days
    DECLARE @days bigint

    SET @days = FLOOR(ABS(@ticks / 864000000000.0))

    IF (@days > 0)
    BEGIN
        SET @timeSpanString = @timeSpanString + CONVERT(varchar(26), @days) + '.'
    END

    SET @ticks = ABS(@ticks % 864000000000)
    -- Hours
    SET @timeSpanString = @timeSpanString + RIGHT('0' + CONVERT(varchar(26), FLOOR(@ticks / 36000000000.0)), 2) + ':'
    SET @ticks = @ticks % 36000000000
    -- Minutes
    SET @timeSpanString = @timeSpanString + RIGHT('0' + CONVERT(varchar(26), FLOOR(@ticks / 600000000.0)), 2) + ':'
    SET @ticks = @ticks % 600000000
    -- Seconds
    SET @timeSpanString = @timeSpanString + RIGHT('0' + CONVERT(varchar(26), FLOOR(@ticks / 10000000.0)), 2)
    SET @ticks = @ticks % 10000000

    -- Fractional Seconds
    IF (@ticks > 0)
    BEGIN
        SET @timeSpanString = @timeSpanString + '.' + LEFT(CONVERT(varchar(26), @ticks) + '0000000', 7)
    END

    RETURN @timeSpanString
END
GO

-- =============================================
-- Author:      James Coe
-- Create date: 2011-05-23
-- Description: Adds the specified number of 100 nanosecond ticks to a date.
-- =============================================
CREATE FUNCTION [dbo].[DateAddTicks] (
    @ticks bigint
    , @starting_date datetimeoffset
    )
RETURNS datetimeoffset
AS
BEGIN
    DECLARE @dateTimeResult datetimeoffset

    IF (@ticks < 0)
    BEGIN
        -- Hours
        SET @dateTimeResult = DATEADD(HOUR, CEILING(@ticks / 36000000000.0), @starting_date)
        SET @ticks = @ticks % 36000000000
        -- Seconds
        SET @dateTimeResult = DATEADD(SECOND, CEILING(@ticks / 10000000.0), @dateTimeResult)
        SET @ticks = @ticks % 10000000
        -- Nanoseconds
        SET @dateTimeResult = DATEADD(NANOSECOND, @ticks * 100, @dateTimeResult)
    END
    ELSE
    BEGIN
        -- Hours
        SET @dateTimeResult = DATEADD(HOUR, FLOOR(@ticks / 36000000000.0), @starting_date)
        SET @ticks = @ticks % 36000000000
        -- Seconds
        SET @dateTimeResult = DATEADD(SECOND, FLOOR(@ticks / 10000000.0), @dateTimeResult)
        SET @ticks = @ticks % 10000000
        -- Nanoseconds
        SET @dateTimeResult = DATEADD(NANOSECOND, @ticks * 100, @dateTimeResult)
    END

    RETURN @dateTimeResult
END
GO

-- =============================================
-- Author:      James Coe
-- Create date: 2011-05-23
-- Description:  Gets the difference between two dates in 100 nanosecond ticks.
-- =============================================
CREATE FUNCTION [dbo].[DateDiffTicks] (
    @starting_date datetimeoffset
    , @ending_date datetimeoffset
    )
RETURNS bigint
AS
BEGIN
    DECLARE @ticks bigint
    DECLARE @days bigint
    DECLARE @hours bigint
    DECLARE @minutes bigint
    DECLARE @seconds bigint

    SET @hours = DATEDIFF(HOUR, @starting_date, @ending_date)
    SET @starting_date = DATEADD(HOUR, @hours, @starting_date)
    SET @ticks = @hours * 36000000000
    SET @seconds = DATEDIFF(SECOND, @starting_date, @ending_date)
    SET @starting_date = DATEADD(SECOND, @seconds, @starting_date)
    SET @ticks = @ticks + @seconds * 10000000
    SET @ticks = @ticks + CONVERT(bigint, DATEDIFF(NANOSECOND, @starting_date, @ending_date)) / 100

    RETURN @ticks
END
GO

--- BEGIN Test Harness ---
SET NOCOUNT ON

DECLARE @dateTimeOffsetMinValue datetimeoffset
DECLARE @dateTimeOffsetMaxValue datetimeoffset
DECLARE @timeSpanMinValueString varchar(26)
DECLARE @timeSpanZeroString varchar(26)
DECLARE @timeSpanMaxValueString varchar(26)
DECLARE @timeSpanMinValueTicks bigint
DECLARE @timeSpanZeroTicks bigint
DECLARE @timeSpanMaxValueTicks bigint
DECLARE @dateTimeOffsetMinMaxDiffTicks bigint
DECLARE @dateTimeOffsetMaxMinDiffTicks bigint

SET @dateTimeOffsetMinValue = '0001-01-01T00:00:00.0000000+00:00'
SET @dateTimeOffsetMaxValue = '9999-12-31T23:59:59.9999999+00:00'
SET @timeSpanMinValueString = '-10675199.02:48:05.4775808'
SET @timeSpanZeroString = '00:00:00'
SET @timeSpanMaxValueString = '10675199.02:48:05.4775807'
SET @timeSpanMinValueTicks = -9223372036854775808
SET @timeSpanZeroTicks = 0
SET @timeSpanMaxValueTicks = 9223372036854775807
SET @dateTimeOffsetMinMaxDiffTicks = 3155378975999999999
SET @dateTimeOffsetMaxMinDiffTicks = -3155378975999999999

-- TimeSpan Conversion Tests
PRINT 'Testing TimeSpan conversions...'

DECLARE @convertToTimeSpanStringMinTicksResult varchar(26)
DECLARE @convertFromTimeSpanStringMinTimeSpanResult bigint
DECLARE @convertToTimeSpanStringZeroTicksResult varchar(26)
DECLARE @convertFromTimeSpanStringZeroTimeSpanResult bigint
DECLARE @convertToTimeSpanStringMaxTicksResult varchar(26)
DECLARE @convertFromTimeSpanStringMaxTimeSpanResult bigint

SET @convertToTimeSpanStringMinTicksResult = dbo.ConvertToTimeSpanString(@timeSpanMinValueTicks)
SET @convertFromTimeSpanStringMinTimeSpanResult = dbo.ConvertFromTimeSpanString(@timeSpanMinValueString)
SET @convertToTimeSpanStringZeroTicksResult = dbo.ConvertToTimeSpanString(@timeSpanZeroTicks)
SET @convertFromTimeSpanStringZeroTimeSpanResult = dbo.ConvertFromTimeSpanString(@timeSpanZeroString)
SET @convertToTimeSpanStringMaxTicksResult = dbo.ConvertToTimeSpanString(@timeSpanMaxValueTicks)
SET @convertFromTimeSpanStringMaxTimeSpanResult = dbo.ConvertFromTimeSpanString(@timeSpanMaxValueString)

-- Test Results
SELECT 'Convert to TimeSpan String from Ticks (Minimum)' AS Test
    , CASE 
        WHEN @convertToTimeSpanStringMinTicksResult = @timeSpanMinValueString
            THEN 'Pass'
        ELSE 'Fail'
        END AS [Test Status]
    , @timeSpanMinValueTicks AS [Ticks]
    , CONVERT(varchar(26), NULL) AS [TimeSpan String]
    , CONVERT(varchar(26), @convertToTimeSpanStringMinTicksResult) AS [Actual Result]
    , CONVERT(varchar(26), @timeSpanMinValueString) AS [Expected Result]
UNION ALL
SELECT 'Convert from TimeSpan String to Ticks (Minimum)' AS Test
    , CASE 
        WHEN @convertFromTimeSpanStringMinTimeSpanResult = @timeSpanMinValueTicks
            THEN 'Pass'
        ELSE 'Fail'
        END AS [Test Status]
    , NULL AS [Ticks]
    , @timeSpanMinValueString AS [TimeSpan String]
    , CONVERT(varchar(26), @convertFromTimeSpanStringMinTimeSpanResult) AS [Actual Result]
    , CONVERT(varchar(26), @timeSpanMinValueTicks) AS [Expected Result]
UNION ALL
SELECT 'Convert to TimeSpan String from Ticks (Zero)' AS Test
    , CASE 
        WHEN @convertToTimeSpanStringZeroTicksResult = @timeSpanZeroString
            THEN 'Pass'
        ELSE 'Fail'
        END AS [Test Status]
    , @timeSpanZeroTicks AS [Ticks]
    , CONVERT(varchar(26), NULL) AS [TimeSpan String]
    , CONVERT(varchar(26), @convertToTimeSpanStringZeroTicksResult) AS [Actual Result]
    , CONVERT(varchar(26), @timeSpanZeroString) AS [Expected Result]
UNION ALL
SELECT 'Convert from TimeSpan String to Ticks (Zero)' AS Test
    , CASE 
        WHEN @convertFromTimeSpanStringZeroTimeSpanResult = @timeSpanZeroTicks
            THEN 'Pass'
        ELSE 'Fail'
        END AS [Test Status]
    , NULL AS [Ticks]
    , @timeSpanZeroString AS [TimeSpan String]
    , CONVERT(varchar(26), @convertFromTimeSpanStringZeroTimeSpanResult) AS [Actual Result]
    , CONVERT(varchar(26), @timeSpanZeroTicks) AS [Expected Result]
UNION ALL
SELECT 'Convert to TimeSpan String from Ticks (Maximum)' AS Test
    , CASE 
        WHEN @convertToTimeSpanStringMaxTicksResult = @timeSpanMaxValueString
            THEN 'Pass'
        ELSE 'Fail'
        END AS [Test Status]
    , @timeSpanMaxValueTicks AS [Ticks]
    , CONVERT(varchar(26), NULL) AS [TimeSpan String]
    , CONVERT(varchar(26), @convertToTimeSpanStringMaxTicksResult) AS [Actual Result]
    , CONVERT(varchar(26), @timeSpanMaxValueString) AS [Expected Result]
UNION ALL
SELECT 'Convert from TimeSpan String to Ticks (Maximum)' AS Test
    , CASE 
        WHEN @convertFromTimeSpanStringMaxTimeSpanResult = @timeSpanMaxValueTicks
            THEN 'Pass'
        ELSE 'Fail'
        END AS [Test Status]
    , NULL AS [Ticks]
    , @timeSpanMaxValueString AS [TimeSpan String]
    , CONVERT(varchar(26), @convertFromTimeSpanStringMaxTimeSpanResult) AS [Actual Result]
    , CONVERT(varchar(26), @timeSpanMaxValueTicks) AS [Expected Result]

-- Ticks Date Add Test
PRINT 'Testing DateAddTicks...'

DECLARE @DateAddTicksPositiveTicksResult datetimeoffset
DECLARE @DateAddTicksZeroTicksResult datetimeoffset
DECLARE @DateAddTicksNegativeTicksResult datetimeoffset

SET @DateAddTicksPositiveTicksResult = dbo.DateAddTicks(@dateTimeOffsetMinMaxDiffTicks, @dateTimeOffsetMinValue)
SET @DateAddTicksZeroTicksResult = dbo.DateAddTicks(@timeSpanZeroTicks, @dateTimeOffsetMinValue)
SET @DateAddTicksNegativeTicksResult = dbo.DateAddTicks(@dateTimeOffsetMaxMinDiffTicks, @dateTimeOffsetMaxValue)

-- Test Results
SELECT 'Date Add with Ticks Test (Positive)' AS Test
    , CASE 
        WHEN @DateAddTicksPositiveTicksResult = @dateTimeOffsetMaxValue
            THEN 'Pass'
        ELSE 'Fail'
        END AS [Test Status]
    , @dateTimeOffsetMinMaxDiffTicks AS [Ticks]
    , @dateTimeOffsetMinValue AS [Starting Date]
    , @DateAddTicksPositiveTicksResult AS [Actual Result]
    , @dateTimeOffsetMaxValue AS [Expected Result]
UNION ALL
SELECT 'Date Add with Ticks Test (Zero)' AS Test
    , CASE 
        WHEN @DateAddTicksZeroTicksResult = @dateTimeOffsetMinValue
            THEN 'Pass'
        ELSE 'Fail'
        END AS [Test Status]
    , @timeSpanZeroTicks AS [Ticks]
    , @dateTimeOffsetMinValue AS [Starting Date]
    , @DateAddTicksZeroTicksResult AS [Actual Result]
    , @dateTimeOffsetMinValue AS [Expected Result]
UNION ALL
SELECT 'Date Add with Ticks Test (Negative)' AS Test
    , CASE 
        WHEN @DateAddTicksNegativeTicksResult = @dateTimeOffsetMinValue
            THEN 'Pass'
        ELSE 'Fail'
        END AS [Test Status]
    , @dateTimeOffsetMaxMinDiffTicks AS [Ticks]
    , @dateTimeOffsetMaxValue AS [Starting Date]
    , @DateAddTicksNegativeTicksResult AS [Actual Result]
    , @dateTimeOffsetMinValue AS [Expected Result]

-- Ticks Date Diff Test
PRINT 'Testing Date Diff Ticks...'

DECLARE @dateDiffTicksMinMaxResult bigint
DECLARE @dateDiffTicksMaxMinResult bigint

SET @dateDiffTicksMinMaxResult = dbo.DateDiffTicks(@dateTimeOffsetMinValue, @dateTimeOffsetMaxValue)
SET @dateDiffTicksMaxMinResult = dbo.DateDiffTicks(@dateTimeOffsetMaxValue, @dateTimeOffsetMinValue)

-- Test Results
SELECT 'Date Difference in Ticks Test (Min, Max)' AS Test
    , CASE 
        WHEN @dateDiffTicksMinMaxResult = @dateTimeOffsetMinMaxDiffTicks
            THEN 'Pass'
        ELSE 'Fail'
        END AS [Test Status]
    , @dateTimeOffsetMinValue AS [Starting Date]
    , @dateTimeOffsetMaxValue AS [Ending Date]
    , @dateDiffTicksMinMaxResult AS [Actual Result]
    , @dateTimeOffsetMinMaxDiffTicks AS [Expected Result]
UNION ALL
SELECT 'Date Difference in Ticks Test (Max, Min)' AS Test
    , CASE 
        WHEN @dateDiffTicksMaxMinResult = @dateTimeOffsetMaxMinDiffTicks
            THEN 'Pass'
        ELSE 'Fail'
        END AS [Test Status]
    , @dateTimeOffsetMaxValue AS [Starting Date]
    , @dateTimeOffsetMinValue AS [Ending Date]
    , @dateDiffTicksMaxMinResult AS [Actual Result]
    , @dateTimeOffsetMaxMinDiffTicks AS [Expected Result]

PRINT 'Tests Complete.'
GO
--- END Test Harness ---
JamieSee
źródło