Loại SQL chính xác để lưu trữ Thời gian .Net có giá trị> 24:00:00 là gì?


196

Tôi đang cố gắng lưu trữ .Net TimeSpantrong máy chủ SQL 2008 R2.

Mã EF Đầu tiên dường như gợi ý rằng nó nên được lưu trữ dưới dạng Time(7)SQL.

Tuy nhiên, TimeSpantrong .Net có thể xử lý thời gian dài hơn 24 giờ.

Cách tốt nhất để xử lý việc lưu trữ .Net TimeSpantrong máy chủ SQL là gì?


15
Tôi đang sử dụng nó để lưu trữ thời lượng của các sự kiện định kỳ. Do đó, tôi muốn ghi lại thời lượng của sự kiện độc lập với ngày
GraemeMiller


1
Liên quan không trùng lặp. Tôi đã viết cả hai. Một là về Code First và cách thay đổi bản đồ cho TimeSpan. Khác là về thực tế .Net loại Timespan sang ánh xạ SQL.
GraemeMiller 16/12/13

Câu trả lời:


222

Tôi sẽ lưu trữ nó trong cơ sở dữ liệu dưới dạng BIGINTvà tôi sẽ lưu trữ số lượng bọ ve (ví dụ: thuộc tính TimeSpan.Ticks ).

Bằng cách đó, nếu tôi muốn lấy một đối tượng TimeSpan khi tôi truy xuất nó, tôi có thể thực hiện TimeSpan.FromTicks (giá trị) một cách dễ dàng.


3
Làm thế nào bạn sẽ xử lý các tính toán trong sql cho phép bạn cần tính toán bao nhiêu giờ?
Peter

10
Tôi có thể chuyển đổi các dấu tick thành một đối tượng thời gian như thế này : SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME). Các '1900-01-01'ngày không quan trọng, tất nhiên, nó chỉ là biến thứ ba theo yêu cầu của DATEADD(...)chức năng. Hãy nhớ rằng có 100 nano giây trong một tích tắc, nhưng nếu bạn sử dụng, DATEADD(NANOSECOND...bạn có khả năng bị tràn, do đó sử dụng mili giây. Cũng nên nhớ rằng bạn nên kiểm tra thực tế này bằng C # TimeSpan.TicksPerMillisecond(nên là 10000) để chắc chắn.
Tom Chantler

Một tùy chọn là lưu trữ nó dưới dạng một chuỗi, sau đó bạn có thể tải nó bằng TimeSpan.Pude (văn bản). không lý tưởng từ phối cảnh kích thước hoặc truy vấn SQL nhưng có thể được phân tích cú pháp trong TSQL nếu cần
Walter Vehoeven

65

Cảm ơn vì lời khuyên. Vì không có máy chủ SQL tương đương. Tôi chỉ đơn giản tạo một trường thứ 2 đã chuyển đổi TimeSpan thành tick và lưu trữ nó trong DB. Sau đó tôi đã ngăn việc lưu trữ TimeSpan

public Int64 ValidityPeriodTicks { get; set; }

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

6
Ngoài ra, đối với bất kỳ ai sử dụng EF Core - trong 2.1, bạn có thể sử dụng chuyển đổi giá trị và TimeSpanToTicksConverter để ánh xạ thời gian để đánh dấu trong cơ sở dữ liệu một cách minh bạch
GraemeMiller

30

Nếu bạn không phải lưu trữ hơn 24 giờ, bạn có thể lưu trữ thời gian , kể từ SQL Server 2008 và sau đó ánh xạ là

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

Không cần chuyển đổi nếu bạn chỉ cần lưu trữ 24 giờ hoặc ít hơn.

Nguồn: http://msdn.microsoft.com/en-us/l Library / cc716729 (v = vs.110) .aspx

Nhưng , nếu bạn muốn lưu trữ hơn 24h, bạn sẽ cần lưu trữ nó trong tích tắc, truy xuất dữ liệu và sau đó chuyển đổi sang TimeSpan. Ví dụ

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

23
Như OP nói, DataType "thời gian" trong SQL Server chỉ hỗ trợ tối đa 24h, anh ấy muốn lưu trữ> 24h
MichelZ

11
Ngoài ra, TimeSpan (.NET) có thể âm trong khi Time (SQL Server) không thể.
Edward

11
Có một sự khác biệt lớn giữa thời gian và thời lượng. Thời gian biểu thị thời gian vào một ngày nhất định trong khi thời lượng là sự khác biệt giữa hai thời điểm. So sánh nó với một vị trí (thời gian) và khoảng cách (thời lượng).
Ramon de Klein

3
^ Chính xác. - TimeLoại SQL không có nghĩa là đại diện cho thời lượng, mà là phần Thời gian của giá trị DateTime; đó là một sự lựa chọn khủng khiếp cho TimeSpan.
BrainSlugs83

19

Không có tương đương trực tiếp. Chỉ cần lưu trữ số lượng, ví dụ số giây hoặc thứ gì đó phù hợp với độ chính xác cần thiết của bạn.


I E. lưu trữ nó dưới dạng float và sử dụng `TimeSpan.FromSeconds` theo msdn.microsoft.com/en-us/l Library
CAD bloke

7

Tôi biết đây là một câu hỏi cũ, nhưng tôi muốn chắc chắn rằng một vài lựa chọn khác được ghi chú.

Vì bạn không thể lưu trữ TimeSpan lớn hơn 24 giờ trong trường kiểu dữ liệu sql thời gian; một vài lựa chọn khác có thể

  1. Sử dụng một varchar (xx) để lưu trữ ToString của TimeSpan. Lợi ích của việc này là độ chính xác không phải được đưa vào kiểu dữ liệu hoặc phép tính, (giây so với mili giây so với ngày so với trận đấu) Tất cả những gì bạn cần là sử dụng TimeSpan.Pude / TryPude. Đây là những gì tôi sẽ làm.

  2. Sử dụng ngày thứ hai, datetime hoặc datetimeoffset, lưu trữ kết quả của ngày đầu tiên + timespan. Đọc từ db là vấn đề của TimeSpan x = SecondDate - FirstDate. Sử dụng tùy chọn này sẽ bảo vệ bạn cho các thư viện truy cập dữ liệu không phải .NET khác truy cập cùng dữ liệu nhưng không hiểu TimeSpans; trong trường hợp bạn có một môi trường như vậy


1
Tùy chọn 2 là âm thanh có thể có ích mỗi giờ và sau đó. thx
rahicks

3

Để phù hợp với những gì có thể là nguồn có khả năng tạo ra khoảng thời gian nhất (tính toán chênh lệch 2 lần hoặc thời gian ngày), bạn có thể muốn lưu trữ .NET TimeSpandưới dạng Máy chủ SQLDateTime Type.

Điều này là do trong SQL Server, sự khác biệt của 2 DateTime's ( Castđể Float' s và sau đó Casttrở lại một DateTime) đơn giản là một làDateTime tương đối so với ngày 1 tháng 1 năm 1900. Ví dụ: Chênh lệch +0,1 giây sẽ là ngày 1 tháng 1 năm 1900 00: 00.100 và -0.1 giây sẽ là ngày 31 tháng 12 năm 1899 23: 59: 59.900.

Để chuyển đổi .NET TimeSpanthành DateTimeLoại máy chủ SQL , trước tiên bạn sẽ chuyển đổi nó thành DateTimeLoại .NET bằng cách thêm nó vào DateTimengày 1 tháng 1 năm 1900. Tất nhiên, khi bạn đọc nó thành .NET từ SQL Server, trước tiên bạn sẽ đọc nó thành .NET DateTimevà trừ đi ngày 1 tháng 1 năm 1900 từ nó để chuyển đổi nó thành .NET TimeSpan.

Đối với các trường hợp sử dụng trong đó khoảng thời gian được tạo từ SQL Server DateTimevà trong SQL Server (tức là thông qua T-SQL) và SQL Server trước năm 2016, tùy thuộc vào phạm vi và nhu cầu chính xác của bạn, có thể không thực tế để lưu trữ chúng dưới dạng mili giây (không đề cập Ticks) vì IntLoại được trả về bởi DateDiff(so với BigInttừ SS 2016 + 'sDateDiff_Big ) tràn sau ~ 24 ngày trị giá mili giây và ~ 67 năm. của giây. Trong khi đó, giải pháp này sẽ xử lý các khoảng thời gian với độ chính xác xuống còn 0,1 giây và từ -147 đến +89999 ..

CẢNH BÁO:

  1. Điều này sẽ chỉ hoạt động nếu sự khác biệt so với ngày 1 tháng 1 năm 1900 sẽ dẫn đến một giá trị trong phạm vi DateTimeLoại Máy chủ SQL (ngày 1 tháng 1 năm 1753 đến ngày 31 tháng 12 năm 9999 hay -147 đến +8,099 năm.). Chúng ta không phải lo lắng nhiều về phía .NET TimeSpan, vì nó có thể giữ từ 29 k đến +29 k yrs. Tôi đã không đề cập đến DateTime2Loại máy chủ SQL (có phạm vi, về mặt tiêu cực, lớn hơn nhiều so với SQL Server DateTime), bởi vì: a) nó không thể được chuyển đổi thành số thông qua một phạm vi đơn giản Castvà b) DateTimenên đủ cho phần lớn các trường hợp sử dụng.

  2. SQL Server DateTimekhác biệt tính thông qua Cast- để - Float- và - Phương pháp lại không có vẻ chính xác hơn 0,1 giây.


Tôi đã quên tôi thậm chí đã đọc Q này ít hơn nhiều khi tôi viết A này và đang tìm kiếm một A một lần nữa. Tôi bắt đầu đọc A này và tự nghĩ: (Wow, đây là câu trả lời tốt nhất cho đến nay!). : D
Tom

3

Có nhiều cách để trình bày một khoảng thời gian trong cơ sở dữ liệu.

thời gian

Kiểu dữ liệu này được hỗ trợ kể từ SQL Server 2008 và là cách ưa thích để lưu trữ a TimeSpan. Không có bản đồ cần thiết. Nó cũng hoạt động tốt với mã SQL.

public TimeSpan ValidityPeriod { get; set; }

Tuy nhiên, như đã nêu trong câu hỏi ban đầu, kiểu dữ liệu này được giới hạn trong 24 giờ.

datetimeoffset

Các datetimeoffsetkiểu dữ liệu ánh xạ trực tiếp đến System.DateTimeOffset. Nó được sử dụng để thể hiện phần bù giữa a datetime/ datetime2to UTC, nhưng bạn cũng có thể sử dụng nó choTimeSpan .

Tuy nhiên, vì kiểu dữ liệu gợi ý một ngữ nghĩa rất cụ thể, vì vậy bạn cũng nên xem xét các tùy chọn khác.

datetime / datetime2

Một cách tiếp cận có thể là sử dụng datetimehoặc datetime2các loại. Điều này là tốt nhất trong các tình huống mà bạn cần xử lý trực tiếp các giá trị trong cơ sở dữ liệu. để xem, thủ tục lưu trữ, hoặc báo cáo. Hạn chế là bạn cần phải trừ đi giá trị DateTime(1900,01,01,00,00,00)từ ngày để lấy lại khoảng thời gian trong logic kinh doanh của bạn.

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

ông lớn

Một cách tiếp cận khác có thể là chuyển đổi TimeSpan thành tick và sử dụng bigintkiểu dữ liệu. Tuy nhiên, cách tiếp cận này có nhược điểm là rất khó sử dụng trong các truy vấn SQL.

public long ValidityPeriod { get; set; }

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

varar (N)

Điều này là tốt nhất cho các trường hợp mà con người nên đọc được giá trị. Bạn cũng có thể sử dụng định dạng này trong các truy vấn SQL bằng cách sử dụng CONVERT(datetime, ValidityPeriod)hàm. Phụ thuộc vào độ chính xác cần thiết, bạn sẽ cần từ 8 đến 25 ký tự.

public string ValidityPeriod { get; set; }

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

Tiền thưởng: Thời gian và Thời lượng

Sử dụng một chuỗi, bạn cũng có thể lưu trữ các kiểu dữ liệu NodaTime , đặc biệt DurationPeriod . Cái đầu tiên về cơ bản giống như TimeSpan, trong khi cái sau tôn trọng rằng một số ngày và tháng dài hơn hoặc ngắn hơn những cái khác (ví dụ: tháng 1 có 31 ngày và tháng 2 có 28 hoặc 29; một số ngày dài hơn hoặc ngắn hơn vì thời gian tiết kiệm ánh sáng ban ngày ). Trong những trường hợp như vậy, sử dụng TimeSpan là lựa chọn sai.

Bạn có thể sử dụng mã này để chuyển đổi Thời gian:

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

Và sau đó sử dụng nó như

public string ValidityPeriod { get; set; }

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

Tôi thực sự thích NodaTimevà nó thường cứu tôi khỏi những lỗi khó khăn và đau đầu. Hạn chế ở đây là bạn thực sự không thể sử dụng nó trong các truy vấn SQL và cần thực hiện các phép tính trong bộ nhớ.

CLR Loại do người dùng xác định

Bạn cũng có tùy chọn để sử dụng kiểu dữ liệu tùy chỉnh và hỗ trợ TimeSpantrực tiếp một lớp tùy chỉnh . Xem các loại do người dùng xác định CLR để biết chi tiết.

Hạn chế ở đây là kiểu dữ liệu có thể không hoạt động tốt với các Báo cáo SQL. Ngoài ra, một số phiên bản của SQL Server (Azure, Linux, Kho dữ liệu) không được hỗ trợ.

Chuyển đổi giá trị

Bắt đầu với EntityFramework Core 2.1, bạn có tùy chọn sử dụng Chuyển đổi giá trị .

Tuy nhiên, khi sử dụng điều này, EF sẽ không thể chuyển đổi nhiều truy vấn thành SQL, khiến các truy vấn chạy trong bộ nhớ; có khả năng chuyển nhiều và rất nhiều dữ liệu vào ứng dụng của bạn.

Vì vậy, ít nhất là bây giờ, tốt hơn hết là không sử dụng nó và chỉ cần ánh xạ kết quả truy vấn với Automapper .


1

Thông thường, tôi lưu trữ TimeSpan dưới dạng một khối lớn với các dấu tick từ thuộc tính TimeSpan.Ticks như đề xuất trước đây. Bạn cũng có thể lưu trữ TimeSpan dưới dạng varchar (26) được điền với đầu ra của TimeSpan.ToString (). Bốn hàm vô hướng (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks) mà tôi đã viết rất hữu ích để xử lý TimeSpan ở phía SQL và tránh các hack sẽ tạo ra các phạm vi giới hạn giả tạo. Nếu bạn có thể lưu trữ khoảng thời gian trong .NET TimeSpan thì nó cũng hoạt động với các chức năng này. Ngoài ra, các chức năng cho phép bạn làm việc với TimeSpans và tích tắc 100 nano giây ngay cả khi sử dụng các công nghệ không bao gồm .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 ---
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.