Was ist der richtige SQL-Typ zum Speichern einer .Net-Zeitspanne mit Werten> 24:00:00?

196

Ich versuche, ein .NET TimeSpanin SQL Server 2008 R2 zu speichern .

EF Code First scheint vorzuschlagen, dass es als Time(7)in SQL gespeichert werden sollte .

In TimeSpan.Net können jedoch längere Zeiträume als 24 Stunden verarbeitet werden.

Was ist der beste Weg, um .Net TimeSpanin SQL Server zu speichern ?

GraemeMiller
quelle
15
Ich verwende es, um die Länge wiederkehrender Ereignisse zu speichern. Deshalb wollte ich die Länge des Ereignisses unabhängig vom Datum
erfassen
1
Verwandt nicht doppelt. Ich habe sie beide geschrieben. In einem geht es um Code First und das Ändern der Karte für TimeSpan. Bei der anderen handelt es sich um die tatsächliche Zuordnung von Zeitspanne zu SQL vom Typ .Net.
GraemeMiller

Antworten:

222

Ich würde es in der Datenbank als BIGINTspeichern und die Anzahl der Ticks speichern (z. B. TimeSpan.Ticks- Eigenschaft).

Auf diese Weise könnte ich, wenn ich beim Abrufen ein TimeSpan-Objekt erhalten möchte, einfach TimeSpan.FromTicks (Wert) ausführen, was einfach wäre.

Tom Chantler
quelle
3
Wie würden Sie mit Berechnungen in SQL umgehen? Nehmen wir an, Sie müssten berechnen, wie viele Stunden es enthält.
Peter
10
Ich würde die Zecken wahrscheinlich in ein Zeitobjekt wie das folgende umwandeln : SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME). Das '1900-01-01'Datum spielt natürlich keine Rolle, es ist nur die dritte Variable, die von der DATEADD(...)Funktion benötigt wird . Denken Sie daran, dass ein Tick 100 Nanosekunden enthält. Wenn Sie jedoch verwenden DATEADD(NANOSECOND..., tritt wahrscheinlich ein Überlauf auf, sodass Millisekunden verwendet werden. Denken Sie auch daran, dass Sie diese Tatsache mit C # TimeSpan.TicksPerMillisecond(sollte 10000 sein) überprüfen sollten, um sicherzugehen.
Tom Chantler
Eine Option ist, es als Zeichenfolge zu speichern. Sie können es dann mit TimeSpan.Parse (Text) laden. Nicht ideal aus Größenperspektive oder SQL-Abfragen, kann aber bei Bedarf in TSQL analysiert werden
Walter Vehoeven
65

Danke für den Hinweis. Da es in SQL Server kein Äquivalent gibt. Ich habe einfach ein zweites Feld erstellt, das die Zeitspanne in Ticks konvertiert und in der Datenbank gespeichert hat. Ich habe dann das Speichern der TimeSpan verhindert

public Int64 ValidityPeriodTicks { get; set; }

[NotMapped]
public TimeSpan ValidityPeriod
{
    get { return TimeSpan.FromTicks(ValidityPeriodTicks); }
    set { ValidityPeriodTicks = value.Ticks; }
}
GraemeMiller
quelle
6
Auch für alle, die EF Core verwenden - in 2.1 können Sie Wertekonvertierungen und TimeSpanToTicksConverter verwenden, um Zeitspannen transparent auf Ticks in der Datenbank
abzubilden
31

Wenn Sie nicht mehr als 24 Stunden speichern müssen , können Sie nur die Zeit speichern , da SQL Server 2008 und höher die Zuordnung ist

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

Keine Konvertierungen erforderlich, wenn Sie nur 24 Stunden oder weniger speichern müssen.

Quelle: http://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx

Aber , wenn Sie mehr als 24 Stunden speichern möchten, gehen Sie Notwendigkeit , sie in Zecken zu speichern, die Daten abrufen und dann in Timespan zu konvertieren. Beispielsweise

int timeData = yourContext.yourTable.FirstOrDefault();
TimeSpan ts = TimeSpan.FromMilliseconds(timeData);
Alejandro del Río
quelle
23
Wie das OP sagt, unterstützt der "Zeit" -Datentyp in SQL Server nur bis zu
24 Stunden
11
Außerdem kann TimeSpan (.NET) negativ sein, Time (SQL Server) jedoch nicht.
Edward
11
Es gibt einen großen Unterschied zwischen einer Zeit und einer Dauer. Die Zeit repräsentiert die Zeit an einem bestimmten Tag, während die Dauer die Differenz zwischen zwei Momenten ist. Vergleichen Sie es mit einem Ort (Zeit) und einer Entfernung (Dauer).
Ramon de Klein
3
^ Genau. - Der SQL- TimeTyp soll nicht eine Dauer darstellen, sondern den Zeitteil eines DateTime-Werts. Es ist eine schreckliche Wahl für TimeSpan.
BrainSlugs83
19

Es gibt kein direktes Äquivalent. Speichern Sie es einfach numerisch, z. B. Anzahl der Sekunden oder etwas, das Ihrer gewünschten Genauigkeit entspricht.

Angst vor einem Hackplaneten
quelle
dh. Speichern Sie es als Float und verwenden Sie "TimeSpan.FromSeconds" gemäß msdn.microsoft.com/en-us/library/…
CAD-
7

Ich weiß, dass dies eine alte Frage ist, aber ich wollte sicherstellen, dass einige andere Optionen angegeben werden.

Da Sie eine Zeitspanne von nicht mehr als 24 Stunden in einem Zeit-SQL-Datentypfeld speichern können; ein paar andere Optionen könnten sein.

  1. Verwenden Sie einen Varchar (xx), um den ToString des TimeSpan zu speichern. Dies hat den Vorteil, dass die Genauigkeit nicht in den Datentyp oder die Berechnung integriert werden muss (Sekunden gegenüber Millisekunden gegenüber Tagen gegenüber vierzehn Tagen). Sie müssen lediglich TimeSpan.Parse / TryParse verwenden. Das würde ich tun.

  2. Verwenden Sie ein zweites Datum, Datum / Uhrzeit oder Datum / Uhrzeit-Versatz, in dem das Ergebnis des ersten Datums + der Zeitspanne gespeichert wird. Das Lesen aus der Datenbank ist eine Frage von TimeSpan x = SecondDate - FirstDate. Wenn Sie diese Option verwenden, werden Sie vor anderen Nicht-.NET-Datenzugriffsbibliotheken geschützt, die auf dieselben Daten zugreifen, TimeSpans jedoch nicht verstehen. falls Sie eine solche Umgebung haben.

Rick
quelle
1
Option 2 klingt so, als wäre es von Zeit zu Zeit nützlich. thx
rahicks
3

Um mit der wahrscheinlich wahrscheinlichsten Quelle für die Generierung einer Zeitspanne übereinzustimmen (Berechnung der Differenz von zwei oder Datums- und Uhrzeitangaben), möchten Sie möglicherweise .NET TimeSpanals SQL Server- DateTimeTyp speichern .

Dies liegt daran, dass in SQL Server die Differenz von 2 DateTime( Castzu Float'und dann Castzurück zu a DateTime) einfach DateTimerelativ zum 1. Januar 1900 ist. Eine Differenz von +0,1 Sekunden wäre der 1. Januar 1900 00: 00: 00.100 und -0,1 Sekunden wäre der 31. Dezember 1899 23: 59: 59.900.

Um ein .NET TimeSpanin einen SQL Server- DateTimeTyp zu konvertieren, konvertieren Sie es zunächst in einen .NET- DateTimeTyp, indem Sie es einem DateTimevom 1. Januar 1900 hinzufügen. Wenn Sie es von SQL Server in .NET einlesen, müssen Sie dies zunächst tun Lesen Sie es in ein .NET DateTimeund subtrahieren Sie dann den 1. Januar 1900 davon, um es in ein .NET zu konvertieren TimeSpan.

In Anwendungsfällen, in denen die Zeitspannen von SQL Server DateTimeund innerhalb von SQL Server (dh über T-SQL) generiert werden und SQL Server vor 2016 liegt, ist es je nach Reichweite und Genauigkeitsanforderungen möglicherweise nicht sinnvoll, sie zu speichern als Millisekunden (ganz zu schweigen davon Ticks), weil der IntTyp, der von DateDiff(im Vergleich zu BigIntSS 2016 + DateDiff_Big) zurückgegeben wurde, nach ~ 24 Tagen im Wert von Millisekunden und ~ 67 Jahren überläuft. von Sekunden. Während diese Lösung Zeitspannen mit einer Genauigkeit von bis zu 0,1 Sekunden und von -147 bis +8.099 Jahren handhabt.

WARNHINWEISE:

  1. Dies würde nur funktionieren, wenn der Unterschied zum 1. Januar 1900 zu einem Wert im Bereich eines SQL Server- DateTimeTyps führen würde (1. Januar 1753 bis 31. Dezember 9999, auch bekannt als -147 bis +8.099 Jahre). Wir müssen uns auf der .NET- TimeSpanSeite nicht so viele Sorgen machen , da es ~ 29 k bis +29 k Jahre halten kann. Ich habe den SQL Server- DateTime2Typ (dessen Bereich auf der negativen Seite viel größer ist als der von SQL Server DateTime) nicht erwähnt, weil: a) er nicht über einen einfachen in einen numerischen Bereich konvertiert werden kann Castund b) DateTimeder Bereich ausreichen sollte für die überwiegende Mehrheit der Anwendungsfälle.

  2. SQL Server- DateTimeUnterschiede, die mit der Methode Cast- to - Float- und - back berechnet wurden, scheinen nach 0,1 Sekunden nicht genau zu sein.

Tom
quelle
Ich habe vergessen, dass ich dieses Q noch viel weniger gelesen habe, als ich dieses A geschrieben habe, und habe wieder nach einem A gesucht. Ich fing an, dieses A zu lesen und dachte mir: (Wow, das ist die beste Antwort bisher!). : D
Tom
3

Es gibt mehrere Möglichkeiten, eine Zeitspanne in der Datenbank darzustellen.

Zeit

Dieser Datentyp wird seit SQL Server 2008 unterstützt und ist die bevorzugte Methode zum Speichern von a TimeSpan. Es ist keine Zuordnung erforderlich. Es funktioniert auch gut mit SQL-Code.

public TimeSpan ValidityPeriod { get; set; }

Wie in der ursprünglichen Frage angegeben, ist dieser Datentyp jedoch auf 24 Stunden begrenzt.

datetimeoffset

Der datetimeoffsetDatentyp wird direkt zugeordnet System.DateTimeOffset. Es wird verwendet, um den Versatz zwischen einem datetime/ datetime2zu UTC auszudrücken , aber Sie können ihn auch für verwenden TimeSpan.

Da der Datentyp jedoch eine sehr spezifische Semantik vorschlägt, sollten Sie auch andere Optionen in Betracht ziehen.

datetime / datetime2

Ein Ansatz könnte darin bestehen, die Typen datetimeoder zu datetime2verwenden. Dies ist am besten in Szenarien, in denen Sie die Werte in der Datenbank direkt verarbeiten müssen, d. H. für Ansichten, gespeicherte Prozeduren oder Berichte. Der Nachteil ist, dass Sie den Wert DateTime(1900,01,01,00,00,00)vom Datum abziehen müssen, um die Zeitspanne in Ihrer Geschäftslogik wiederherzustellen .

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

Ein anderer Ansatz könnte darin bestehen, die Zeitspanne in Ticks zu konvertieren und den bigintDatentyp zu verwenden. Dieser Ansatz hat jedoch den Nachteil, dass die Verwendung in SQL-Abfragen umständlich ist.

public long ValidityPeriod { get; set; }

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

Varchar (N)

Dies ist am besten für Fälle geeignet, in denen der Wert für den Menschen lesbar sein sollte. Sie können dieses Format auch in SQL-Abfragen verwenden, indem Sie die CONVERT(datetime, ValidityPeriod)Funktion verwenden. Abhängig von der erforderlichen Genauigkeit benötigen Sie zwischen 8 und 25 Zeichen.

public string ValidityPeriod { get; set; }

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

Bonus: Zeitraum und Dauer

Mithilfe einer Zeichenfolge können Sie auch NodaTime- Datentypen speichern , insbesondere DurationundPeriod . Die erste ist im Grunde die gleiche wie eine Zeitspanne, während die spätere berücksichtigt, dass einige Tage und Monate länger oder kürzer sind als andere (dh der Januar hat 31 Tage und der Februar 28 oder 29; einige Tage sind wegen der Sommerzeit länger oder kürzer ). In solchen Fällen ist die Verwendung eines TimeSpan die falsche Wahl.

Mit diesem Code können Sie Perioden konvertieren:

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)));
    }
}

Und dann benutze es gerne

public string ValidityPeriod { get; set; }

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

ich mag wirklich NodaTime es und es erspart mir oft knifflige Fehler und viele Kopfschmerzen. Der Nachteil hierbei ist, dass Sie es wirklich nicht in SQL-Abfragen verwenden können und Berechnungen im Arbeitsspeicher durchführen müssen.

Benutzerdefinierter CLR-Typ

Sie haben auch die Möglichkeit, einen benutzerdefinierten Datentyp zu verwenden und eine benutzerdefinierte TimeSpanKlasse direkt zu unterstützen. Weitere Informationen finden Sie unter Benutzerdefinierte CLR-Typen .

Der Nachteil hierbei ist, dass sich der Datentyp möglicherweise nicht gut mit SQL-Berichten verhält. Einige Versionen von SQL Server (Azure, Linux, Data Warehouse) werden ebenfalls nicht unterstützt.

Wertumwandlungen

Beginnend mit EntityFramework - Core 2.1, haben Sie die Möglichkeit , verwenden Wert Conversions .

Wenn Sie dies verwenden, kann EF jedoch nicht viele Abfragen in SQL konvertieren , was dazu führt, dass Abfragen im Arbeitsspeicher ausgeführt werden. möglicherweise viele, viele Daten in Ihre Anwendung übertragen.

Zumindest für den Moment ist es möglicherweise besser, es nicht zu verwenden und das Abfrageergebnis einfach mit Automapper abzubilden .

MovGP0
quelle
1

Normalerweise speichere ich einen TimeSpan als Bigint, der mit Ticks aus der TimeSpan.Ticks-Eigenschaft gefüllt ist, wie zuvor vorgeschlagen. Sie können einen TimeSpan auch als varchar (26) speichern, der mit der Ausgabe von TimeSpan.ToString () gefüllt ist. Die vier Skalarfunktionen (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks), die ich geschrieben habe, sind hilfreich für die Behandlung von TimeSpan auf der SQL-Seite und vermeiden die Hacks, die künstlich begrenzte Bereiche erzeugen würden. Wenn Sie das Intervall überhaupt in einem .NET TimeSpan speichern können, sollte es auch mit diesen Funktionen funktionieren. Darüber hinaus können Sie mit den Funktionen mit TimeSpans und 100-Nanosekunden-Ticks arbeiten, selbst wenn Sie Technologien verwenden, die .NET Framework nicht enthalten.

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
quelle