Quel est le type SQL correct pour stocker un intervalle de temps .Net avec des valeurs> 24:00:00?

196

J'essaie de stocker un .Net TimeSpandans SQL Server 2008 R2.

EF Code First semble suggérer qu'il devrait être stocké Time(7)en SQL.

Cependant, TimeSpandans .Net, il peut gérer des périodes plus longues que 24 heures.

Quelle est la meilleure façon de gérer le stockage de .Net TimeSpandans le serveur SQL?

GraemeMiller
la source
15
Je l'utilise pour stocker la durée des événements récurrents. Par conséquent, je voulais capturer la durée de l'événement indépendamment de la date
GraemeMiller
1
Associé pas en double. Je les ai écrits tous les deux. L'une concerne le code d'abord et la façon de changer la carte pour TimeSpan. L'autre concerne le mappage Timespan vers SQL de type .Net réel.
GraemeMiller

Réponses:

222

Je le stocke dans la base de données en tant que BIGINTet je stocke le nombre de graduations (par exemple, la propriété TimeSpan.Ticks ).

De cette façon, si je voulais obtenir un objet TimeSpan lorsque je le récupère, je pourrais simplement faire TimeSpan.FromTicks (valeur), ce qui serait facile.

Tom Chantler
la source
3
Comment géreriez-vous les calculs en sql, disons que vous aviez besoin de calculer combien d'heures il contient?
Peter
10
Je serais probablement convertir les tiques en un objet de temps comme celui - ci: SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME). La '1900-01-01'date n'a pas d'importance, bien sûr, c'est juste la troisième variable requise par la DATEADD(...)fonction. N'oubliez pas qu'il y a 100 nanosecondes dans une tique, mais si vous utilisez, DATEADD(NANOSECOND...vous risquez d'obtenir un débordement, donc d'utiliser des millisecondes. N'oubliez pas que vous devez vérifier ce fait en utilisant C # TimeSpan.TicksPerMillisecond(devrait être 10000) pour être sûr.
Tom Chantler du
Une option est de le stocker sous forme de chaîne, vous pouvez ensuite le charger en utilisant TimeSpan.Parse (texte). pas idéal du point de vue de la taille ou des requêtes SQL mais peut être analysé dans TSQL si nécessaire
Walter Vehoeven
65

Merci pour le conseil. Comme il n'y a pas d'équivalent dans SQL Server. J'ai simplement créé un 2ème champ qui a converti le TimeSpan en ticks et l'a stocké dans la base de données. J'ai ensuite empêché de stocker le TimeSpan

public Int64 ValidityPeriodTicks { get; set; }

[NotMapped]
public TimeSpan ValidityPeriod
{
    get { return TimeSpan.FromTicks(ValidityPeriodTicks); }
    set { ValidityPeriodTicks = value.Ticks; }
}
GraemeMiller
la source
6
Aussi pour tous ceux qui utilisent EF Core - dans 2.1, vous pouvez utiliser des conversions de valeurs et TimeSpanToTicksConverter pour mapper les intervalles de temps aux ticks dans la base de données de manière transparente
GraemeMiller
30

Si vous n'avez pas à stocker plus de 24 heures, vous pouvez simplement stocker du temps , car SQL Server 2008 et versions ultérieures sont mappés

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

Aucune conversion n'est nécessaire si vous ne devez stocker que 24 heures ou moins.

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

Mais , si vous souhaitez stocker plus de 24h, vous devrez le stocker par ticks, récupérer les données puis les convertir en TimeSpan. Par exemple

int timeData = yourContext.yourTable.FirstOrDefault();
TimeSpan ts = TimeSpan.FromMilliseconds(timeData);
Alejandro del Río
la source
23
Comme le dit l'OP, le DataType "time" dans SQL Server ne prend en charge que jusqu'à 24h, il veut stocker> 24h
MichelZ
11
En outre, TimeSpan (.NET) peut être négatif, contrairement à Time (SQL Server).
Edward
11
Il y a une différence majeure entre un temps et une durée. L'heure représente l'heure d'un certain jour alors que la durée est la différence entre deux moments. Comparez-le à un lieu (temps) et à une distance (durée).
Ramon de Klein
3
^ Exactement. - Le Timetype SQL n'est pas censé représenter une durée, mais la partie Time d'une valeur DateTime; c'est un choix terrible pour TimeSpan.
BrainSlugs83
19

Il n'y a pas d'équivalent direct. Il suffit de le stocker numériquement, par exemple le nombre de secondes ou quelque chose de approprié à la précision requise.

fearofawhackplanet
la source
c'est à dire. stockez-le en tant que flottant et utilisez `TimeSpan.FromSeconds` selon msdn.microsoft.com/en-us/library/…
CAD bloke le
7

Je sais que c'est une vieille question, mais je voulais m'assurer que quelques autres options sont notées.

Étant donné que vous ne pouvez pas stocker un TimeSpan supérieur à 24 heures dans un champ de type de données time sql; quelques autres options pourraient être.

  1. Utilisez un varchar (xx) pour stocker la ToString du TimeSpan. L'avantage de ceci est que la précision n'a pas à être intégrée dans le type de données ou le calcul, (secondes vs millisecondes vs jours vs quinzaines) Tout ce dont vous avez besoin est d'utiliser TimeSpan.Parse / TryParse. Voilà ce que je ferais.

  2. Utilisez une deuxième date, datetime ou datetimeoffset, qui stocke le résultat de la première date + intervalle de temps. La lecture de la base de données est une question de TimeSpan x = SecondDate - FirstDate. L'utilisation de cette option vous protégera pour que d'autres bibliothèques d'accès aux données non .NET accèdent aux mêmes données mais ne comprennent pas les TimeSpans; au cas où vous auriez un tel environnement.

meule
la source
1
L'option 2 semble être utile de temps en temps. thx
rahicks
3

Pour être cohérent avec ce qui est probablement la source la plus probable de génération d'un intervalle de temps (calcul de la différence de 2 fois ou date-heure), vous souhaiterez peut-être stocker un .NET en TimeSpantant que type SQL Server DateTime.

Cela est dû au fait que dans SQL Server, la différence de 2 DateTime( Castà Floatet puis de Castnouveau à a DateTime) est simplement un DateTimerelatif au 1er janvier 1900. Ex. Une différence de +0,1 seconde serait le 1er janvier 1900 00: 00: 00.100 et -0,1 seconde serait le 31 décembre 1899 23: 59: 59.900.

Pour convertir un .NET TimeSpanen un type SQL Server DateTime, vous devez d'abord le convertir en un DateTimetype .NET en l'ajoutant au DateTime1 janvier 1900. Bien sûr, lorsque vous le lisez dans .NET à partir de SQL Server, vous devez d'abord lisez-le dans un .NET DateTimepuis soustrayez-le le 1er janvier 1900 pour le convertir en .NET TimeSpan.

Pour les cas d'utilisation où les intervalles de temps sont générés à partir de SQL Server DateTimeet dans SQL Server (c'est-à-dire via T-SQL) et SQL Server est antérieur à 2016, selon votre plage et vos besoins de précision, il peut ne pas être pratique de les stocker en millisecondes (sans parler Ticks) car le Inttype renvoyé par DateDiff( par rapport aux BigIntSS 2016+ DateDiff_Big) déborde après environ 24 jours de millisecondes et ~ 67 ans. de secondes. Considérant que, cette solution gérera les intervalles de temps avec précision jusqu'à 0,1 seconde et de -147 à +8 099 ans.

AVERTISSEMENTS:

  1. Cela ne fonctionnerait que si la différence par rapport au 1er janvier 1900 se traduisait par une valeur dans la plage d'un type SQL Server DateTime(du 1er janvier 1753 au 31 décembre 9999 aka -147 à +8 099 ans). Nous n'avons pas à nous inquiéter autant du TimeSpancôté .NET , car il peut contenir de ~ 29 k à +29 k ans. Je n'ai pas mentionné le type SQL Server DateTime2(dont la plage, du côté négatif, est beaucoup plus grande que celle de SQL Server DateTime), car: a) il ne peut pas être converti en numérique via un simple Castet b) DateTimela plage devrait suffire pour la grande majorité des cas d'utilisation.

  2. SQL Server DateTimedifférences calculées par le Cast- à - Float- et - méthode de retour ne semble pas être précis au - delà de 0,1 seconde.

À M
la source
J'ai oublié que j'avais même lu ce Q beaucoup moins que j'avais écrit ce A, et je cherchais à nouveau un A. J'ai commencé à lire ce A et je me suis dit: (Wow, c'est la meilleure réponse jusqu'à présent!). :RÉ
Tom
3

Il existe plusieurs façons de présenter un intervalle de temps dans la base de données.

temps

Ce type de données est pris en charge depuis SQL Server 2008 et est le moyen préféré de stocker un fichier TimeSpan. Aucun mappage n'est nécessaire. Il fonctionne également bien avec le code SQL.

public TimeSpan ValidityPeriod { get; set; }

Cependant, comme indiqué dans la question d'origine, ce type de données est limité à 24 heures.

datetimeoffset

Le datetimeoffsettype de données correspond directement à System.DateTimeOffset. Il est utilisé pour exprimer le décalage entre un datetime/ datetime2vers UTC, mais vous pouvez également l'utiliser pour TimeSpan.

Cependant, puisque le type de données suggère une sémantique très spécifique, vous devriez donc également envisager d'autres options.

datetime / datetime2

Une approche pourrait consister à utiliser les types datetimeou datetime2. C'est le meilleur dans les scénarios où vous devez traiter directement les valeurs dans la base de données, c'est-à-dire. pour les vues, les procédures stockées ou les rapports. L'inconvénient est que vous devez soustraire la valeurDateTime(1900,01,01,00,00,00) de la date pour récupérer l'intervalle de temps dans votre logique métier.

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

Une autre approche pourrait être de convertir le TimeSpan en ticks et d'utiliser le biginttype de données. Cependant, cette approche présente l'inconvénient d'être lourde à utiliser dans les requêtes SQL.

public long ValidityPeriod { get; set; }

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

varchar (N)

Ceci est préférable dans les cas où la valeur doit être lisible par l'homme. Vous pouvez également utiliser ce format dans les requêtes SQL en utilisant la CONVERT(datetime, ValidityPeriod)fonction. En fonction de la précision requise, vous aurez besoin de 8 à 25 caractères.

public string ValidityPeriod { get; set; }

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

Bonus: période et durée

À l'aide d'une chaîne, vous pouvez également stocker des types de données NodaTime , en particulierDuration et Period. Le premier est fondamentalement le même qu'un TimeSpan, tandis que le dernier respecte le fait que certains jours et mois sont plus longs ou plus courts que d'autres (c.-à-d. Janvier a 31 jours et février en a 28 ou 29; certains jours sont plus longs ou plus courts en raison de l'heure d'été) ). Dans de tels cas, l'utilisation d'un TimeSpan n'est pas le bon choix.

Vous pouvez utiliser ce code pour convertir des périodes:

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

Et puis utilisez-le comme

public string ValidityPeriod { get; set; }

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

J'aime vraiment NodaTime et cela m'évite souvent des bugs délicats et beaucoup de maux de tête. L'inconvénient ici est que vous ne pouvez vraiment pas l'utiliser dans les requêtes SQL et devez faire des calculs en mémoire.

Type défini par l'utilisateur CLR

Vous avez également la possibilité d'utiliser un type de données personnalisé et de prendre en charge TimeSpandirectement une classe personnalisée . Voir Types définis par l'utilisateur CLR pour plus de détails.

L'inconvénient ici est que le type de données peut ne pas bien se comporter avec les rapports SQL. De plus, certaines versions de SQL Server (Azure, Linux, Data Warehouse) ne sont pas prises en charge.

Conversions de valeur

À partir d'EntityFramework Core 2.1, vous avez la possibilité d'utiliser des conversions de valeur .

Cependant, lors de l'utilisation de cela, EF ne sera pas en mesure de convertir de nombreuses requêtes en SQL, provoquant l'exécution des requêtes en mémoire; en transférant potentiellement beaucoup et beaucoup de données vers votre application.

Donc, au moins pour l'instant, il serait préférable de ne pas l'utiliser et de simplement mapper le résultat de la requête avec Automapper .

MovGP0
la source
1

En règle générale, je stocke un TimeSpan en tant que bigint rempli de graduations de la propriété TimeSpan.Ticks comme suggéré précédemment. Vous pouvez également stocker un TimeSpan en tant que varchar (26) rempli avec la sortie de TimeSpan.ToString (). Les quatre fonctions scalaires (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks) que j'ai écrites sont utiles pour gérer TimeSpan du côté SQL et éviter les hacks qui produiraient des plages limitées artificiellement. Si vous pouvez stocker l'intervalle dans un TimeSpan .NET, cela devrait également fonctionner avec ces fonctions. De plus, les fonctions vous permettent de travailler avec des TimeSpans et des ticks de 100 nanosecondes même lorsque vous utilisez des technologies qui n'incluent pas le .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
la source