Який правильний тип SQL зберігає .Net Timespan зі значеннями> 24:00:00?


196

Я намагаюся зберігати .Net TimeSpanна SQL сервері 2008 R2.

Код EF спершу передбачає, що він повинен зберігатися як Time(7)у SQL.

Однак TimeSpanу .Net може працювати довше, ніж 24 години.

Який найкращий спосіб обробити збереження .Net TimeSpanна SQL сервері?


15
Я використовую його для зберігання тривалості повторюваних подій. Тому я хотів зафіксувати тривалість події незалежно від дати
GraemeMiller


1
Пов’язані не дублюються. Я написав їх обох. Один про Code First і про те, як змінити карту для TimeSpan. Інша стосується фактичного .Net типу Timespan до SQL-відображення.
GraemeMiller

Відповіді:


223

Я б зберігав його в базі даних у вигляді BIGINTі я б зберігав кількість тиків (наприклад, властивість TimeSpan.Ticks ).

Таким чином, якби я хотів отримати об’єкт TimeSpan, коли його отримував, я міг би просто зробити TimeSpan.FromTicks (значення), що було б легко.


3
Як би ви обробляли обчислення в sql, скажімо, вам потрібно обчислити, скільки годин він містить?
Пітер

10
Я б , ймовірно , перетворити тики в об'єкт часу , як це: SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME). '1900-01-01'Дата не має значення, звичайно, це всього лише третя змінна вимагає DATEADD(...)функції. Пам'ятайте, що в галочці є 100 наносекунд, але якщо DATEADD(NANOSECOND...ви користуєтеся, швидше за все, ви отримаєте перелив, отже, використовуйте мілісекунди. Також пам’ятайте, що ви повинні перевірити цей факт, використовуючи C # TimeSpan.TicksPerMillisecond(має бути 10000), щоб бути впевненим.
Том Чантлер

Опція зберігає її як рядок, потім можна завантажити її за допомогою TimeSpan.Parse (текст). не ідеально з точки зору розміру або SQL querys, але при необхідності можна проаналізувати в TSQL
Walter Vehoeven

65

Дякую за пораду. Так як немає еквівалента на SQL-сервері. Я просто створив 2-е поле, яке перетворило TimeSpan на тики і зберегло його в БД. Тоді мені завадило зберігати TimeSpan

public Int64 ValidityPeriodTicks { get; set; }

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

6
Також для всіх, хто використовує EF Core - у 2.1 ви можете використовувати конверсії значень та TimeSpanToTicksConverter для прозорого відображення
часових просторів

30

Якщо вам не доведеться зберігати більше 24 годин, ви можете просто зберігати час , оскільки це відображення в SQL Server 2008 і пізніших версіях

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

Конверсії не потрібні, якщо вам потрібно зберігати лише 24 години або менше.

Джерело: http://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx

Але , якщо ви хочете зберігати більше 24 годин, вам потрібно буде зберігати їх у кліщах, отримувати дані та потім конвертувати у TimeSpan. Наприклад

int timeData = yourContext.yourTable.FirstOrDefault();
TimeSpan ts = TimeSpan.FromMilliseconds(timeData);

23
Як говорить ОП, DataType "час" у SQL Server підтримує лише до 24 годин, він хоче зберігати> 24 години
MichelZ

11
Також TimeSpan (.NET) може бути негативним, тоді як Time (SQL Server) не може.
Едвард

11
Існує велика різниця між часом і тривалістю. Час представляє час у певний день, тоді як тривалість - це різниця між двома моментами. Порівняйте його з місцем розташування (час) та відстані (тривалість).
Рамон де Кляйн

3
^ Точно. - Timeтип SQL призначений не для відображення тривалості, а для частини часу значення DateTime; це страшний вибір для TimeSpan.
BrainSlugs83

19

Не існує прямого еквівалента. Просто зберігайте його в цифровій формі, наприклад, кількість секунд або щось, що відповідає вашій необхідній точності.


тобто. збережіть його як плаваючий елемент
CAD

7

Я знаю, що це давнє запитання, але я хотів переконатися, що відмічено пару інших варіантів.

Оскільки ви не можете зберігати TimeSpan більше 24 годин у полі даних типу sql; може бути кілька інших варіантів.

  1. Використовуйте varchar (xx) для зберігання ToString TimeSpan. Перевага цього полягає в тому, що точність не повинна вкладатися в тип даних або обчислення, (секунди проти мілісекунд проти днів проти фортенатів) Все, що вам потрібно - це використовувати TimeSpan.Parse / TryParse. Це я би робив.

  2. Використовуйте другу дату, час відміни дати або зсув дати, який зберігає результат першої дати + проміжок часу. Читання з db - це питання TimeSpan x = SecondDate - FirstDate. Використання цієї опції захистить вас від інших бібліотек доступу до даних .NET, які отримують доступ до тих же даних, але не розуміють TimeSpans; на випадок, якщо у вас таке середовище.


1
Варіант 2 - це звуки, схожі на те, що вони можуть стати в нагоді раз у раз. thx
rahicks

3

Щоб відповідати тому, що, ймовірно, є найбільш вірогідним джерелом генерування часового проміжку (обчислення різниці в 2 рази або дати), ви можете зберегти .NET TimeSpanяк SQL ServerDateTime тип .

Це тому, що в SQL Server різниця 2 DateTime's ( Castдо Float', а потім Castназад до a DateTime) просто DateTimeвідносна 1 січня 1900 р. Наприклад. Різниця в +0,1 секунди склала б 1 січня 1900 р. 00: 00: 00,100 та –0,1 секунди - 31 грудня 1899 року 23: 59: 59,900.

Щоб перетворити .NET TimeSpanу DateTimeтип SQL Server , спершу слід перетворити його у DateTimeтип .NET , додавши його до DateTime1 січня 1900 р. Звичайно, коли ви читаєте його у .NET із SQL Server, то спочатку прочитайте його у .NET, DateTimeа потім відніміть 1 січня 1900 року для перетворення його у .NET TimeSpan.

Для випадків використання, коли генеруються часові проміжки від SQL Server DateTimeі в SQL Server (тобто через T-SQL) і SQL Server, це до 2016 року, залежно від вашого діапазону та точності, можливо, зберігання їх може бути не практичним. як мілісекунди (не кажучи вже про те, Ticksщо IntТип, повернутий DateDiff(порівняно BigIntз SS 2016 + 's DateDiff_Big), переповнюється через ~ 24 дні в мілісекундах і ~ 67 років. секунд. Тоді як це рішення обробляє часові проміжки з точністю до 0,1 секунди і від -147 до +8,099 р.

ПОПЕРЕДЖЕННЯ:

  1. Це спрацює лише в тому випадку, якщо різниця відносно 1 січня 1900 р. DateTimeПризведе до значення в межах діапазону типу сервера SQL (1 січня 1753 р. По 31 грудня 9999 р., Від -147 до +8,099 р.). Нам не потрібно турбуватися близько на TimeSpanстороні .NET , оскільки він може тривати від 29 к до +29 кр. Я не згадував про DateTime2тип SQL Server (діапазон якого з негативної сторони значно більший, ніж у SQL Server DateTime), оскільки: а) його не можна перетворити на числовий через простий, Castа b) DateTimeдіапазон повинен бути достатнім для переважної більшості випадків використання.

  2. DateTimeВідмінності SQL Server, обчислені методом « Castдо - Floatі - назад», не здаються точними за 0,1 секунди.


Я забув, що навіть прочитав цю Q набагато менше, ніж написав цю A, і знову шукав A. Я почав читати це «А» і подумав собі: (Ух, це найкраща відповідь поки що!). : D
Том

3

Існує кілька способів представити часовий проміжок часу в базі даних.

час

Цей тип даних підтримується з SQL Server 2008 і є кращим способом зберігання TimeSpan. Не потрібно картування. Він також добре працює з кодом SQL.

public TimeSpan ValidityPeriod { get; set; }

Однак, як зазначено в оригінальному запитанні, цей тип даних обмежений до 24 годин.

зсув дати

Тип datetimeoffsetданих відображається безпосередньо в System.DateTimeOffset. Він використовується для вираження зміщення між a datetime/ datetime2to UTC, але ви також можете використовувати його дляTimeSpan .

Однак, оскільки тип даних передбачає дуже специфічну семантичну ознаку, тому слід також розглянути інші варіанти.

datetime / datetime2

Одним із підходів може бути використання типів datetimeабо datetime2. Це найкраще в сценаріях, де потрібно обробляти значення безпосередньо в базі даних, тобто. для переглядів, збережених процедур або звітів. Недолік полягає в тому, що потрібно повернути значення DateTime(1900,01,01,00,00,00)з дати, щоб повернути часовий проміжок у вашій бізнес-логіці.

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

Іншим підходом може бути перетворення TimeSpan в тики та використання bigintтипу даних. Однак у цього підходу є недолік, який громіздко використовувати у запитах SQL.

public long ValidityPeriod { get; set; }

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

варчар (N)

Це найкраще для тих випадків, коли цінність повинна читати людина. Ви також можете використовувати цей формат у SQL-запитах, використовуючи CONVERT(datetime, ValidityPeriod)функцію. Залежно від необхідної точності, вам знадобиться від 8 до 25 символів.

public string ValidityPeriod { get; set; }

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

Бонус: Період та тривалість

Використовуючи рядок, ви також можете зберігати типи даних NodaTime , особливо DurationтаPeriod . Перший в основному такий самий, як TimeSpan, тоді як пізніший вважає, що деякі дні і місяці довші або коротші, ніж інші (тобто січень має 31 день, а лютий - 28 або 29; деякі дні довші або коротші через літній час ). У таких випадках використання TimeSpan - неправильний вибір.

Ви можете використовувати цей код для перетворення періодів:

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

А потім використовуйте як

public string ValidityPeriod { get; set; }

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

мені дійсно подобається NodaTime і це часто рятує мене від хитрих помилок і багато головного болю. Недолік тут в тому, що ви дійсно не можете використовувати його в SQL-запитах і вам потрібно робити обчислення в пам'яті.

Тип, визначений користувачем CLR

Також у вас є можливість використовувати спеціальний тип даних та безпосередньо підтримувати спеціальний TimeSpanклас. Докладніше див. CLR, визначені користувачем .

Недолік тут полягає в тому, що тип даних може не працювати добре з SQL Reports. Також деякі версії SQL Server (Azure, Linux, Склад даних) не підтримуються.

Конверсії цінностей

Починаючи з EntityFramework Core 2.1, у вас є можливість використовувати конверсії цінностей .

Однак, використовуючи це, EF не зможе перетворити багато запитів у SQL, внаслідок чого запити запускаються в пам'ять; потенційно передаючи багато та багато даних у вашу програму.

Отож, принаймні поки що, можливо, краще не використовувати його, а просто зіставити результат запиту за допомогою Automapper .


1

Як правило, я зберігаю TimeSpan як bigint, заповнений кліщами з властивості TimeSpan.Ticks, як було запропоновано раніше. Ви також можете зберігати TimeSpan у вигляді варшара (26), заповненого результатом TimeSpan.ToString (). Чотири скалярні функції (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks), які я написав, корисні для обробки TimeSpan на стороні SQL і уникають хак, які створюють штучно обмежені діапазони. Якщо ви взагалі можете зберігати інтервал у .NET TimeSpan, він також повинен працювати з цими функціями. Крім того, функції дозволяють вам працювати з TimeSpans і 100-наносекундними кліщами навіть при використанні технологій, що не включають .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 ---
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.