Apa tipe SQL yang benar untuk menyimpan .pan TimesNet dengan nilai> 24:00:00?

196

Saya mencoba untuk menyimpan. Net TimeSpandi SQL server 2008 R2.

EF Code First tampaknya menyarankan itu harus disimpan Time(7)dalam SQL.

Namun TimeSpandalam .Net dapat menangani periode lebih lama dari 24 jam.

Apa cara terbaik untuk menangani penyimpanan .Net TimeSpandi SQL server?

GraemeMiller
sumber
15
Saya menggunakannya untuk menyimpan lamanya acara berulang. Karena itu saya ingin mengabadikan lamanya acara independen tanggal tersebut
GraemeMiller
1
Terkait bukan duplikat. Saya menulis keduanya. Salah satunya adalah tentang Kode Pertama dan cara mengubah peta untuk TimeSpan. Yang lain adalah tentang .Net jenis Timespan ke SQL pemetaan aktual.
GraemeMiller

Jawaban:

222

Saya akan menyimpannya di database sebagai BIGINTdan saya akan menyimpan jumlah kutu (misalnya properti TimeSpan.Ticks ).

Dengan begitu, jika saya ingin mendapatkan objek TimeSpan ketika saya mengambilnya, saya bisa melakukan TimeSpan.FromTicks (nilai) yang akan mudah.

Tom Chantler
sumber
3
Bagaimana Anda menangani perhitungan dalam sql katakanlah Anda perlu menghitung berapa jam di dalamnya?
Peter
10
Saya mungkin akan mengubah kutu menjadi objek saat seperti ini: SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME). The '1900-01-01'tanggal tidak peduli, tentu saja, itu hanya variabel ketiga yang dibutuhkan oleh DATEADD(...)fungsi. Ingat ada 100 nanodetik dalam kutu, tetapi jika Anda menggunakan DATEADD(NANOSECOND...Anda kemungkinan akan mendapatkan luapan, maka gunakan milidetik. Juga ingat bahwa Anda harus memeriksa fakta ini menggunakan C # TimeSpan.TicksPerMillisecond(harus 10.000) untuk memastikan.
Tom Chantler
Opsi adalah menyimpannya sebagai string, Anda kemudian dapat memuatnya menggunakan TimeSpan.Parse (teks). tidak ideal dari perspektif ukuran atau kueri SQL tetapi dapat diuraikan dalam TSQL jika diperlukan
Walter Vehoeven
65

Terima kasih atas sarannya. Karena tidak ada padanan dalam SQL server. Saya hanya membuat bidang ke-2 yang mengubah TimeSpan menjadi ticks dan menyimpannya dalam DB. Saya kemudian mencegah menyimpan TimeSpan

public Int64 ValidityPeriodTicks { get; set; }

[NotMapped]
public TimeSpan ValidityPeriod
{
    get { return TimeSpan.FromTicks(ValidityPeriodTicks); }
    set { ValidityPeriodTicks = value.Ticks; }
}
GraemeMiller
sumber
6
Juga bagi siapa saja yang menggunakan EF Core - dalam 2.1 Anda dapat menggunakan konversi nilai dan TimeSpanToTicksConverter untuk memetakan rentang waktu untuk menandai di dalam basis data secara transparan
GraemeMiller
30

Jika Anda tidak perlu menyimpan lebih dari 24 jam, Anda bisa menyimpan waktu , karena SQL Server 2008 dan kemudian pemetaannya

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

Tidak perlu konversi jika Anda hanya perlu menyimpan 24 jam atau kurang.

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

Tetapi , jika Anda ingin menyimpan lebih dari 24 jam, Anda harus menyimpannya dalam kutu, ambil data dan kemudian konversikan ke TimeSpan. Sebagai contoh

int timeData = yourContext.yourTable.FirstOrDefault();
TimeSpan ts = TimeSpan.FromMilliseconds(timeData);
Alejandro del Río
sumber
23
Seperti kata OP, "waktu" DataType di SQL Server hanya mendukung hingga 24jam, ia ingin menyimpan> 24jam
MichelZ
11
Juga, TimeSpan (.NET) bisa negatif sedangkan Time (SQL Server) tidak bisa.
Edward
11
Ada perbedaan besar antara waktu dan durasi. Waktu mewakili waktu pada hari tertentu sedangkan durasinya adalah perbedaan antara dua momen. Bandingkan dengan lokasi (waktu) dan jarak (durasi).
Ramon de Klein
3
^ Tepat. - TimeTipe SQL tidak dimaksudkan untuk mewakili durasi, tetapi bagian Waktu dari nilai DateTime; itu pilihan yang buruk TimeSpan.
BrainSlugs83
19

Tidak ada padanan langsung. Simpan saja secara numerik, mis. Jumlah detik atau sesuatu yang sesuai dengan akurasi yang Anda butuhkan.

planet fearofawhack
sumber
yaitu. simpan sebagai pelampung dan gunakan `TimeSpan.FromSeconds` sesuai msdn.microsoft.com/en-us/library/…
CAD bloke
7

Saya tahu ini adalah pertanyaan lama, tetapi saya ingin memastikan beberapa opsi lain dicatat.

Karena Anda tidak dapat menyimpan TimeSpan lebih dari 24 jam dalam bidang datatype sql waktu; beberapa opsi lain mungkin.

  1. Gunakan varchar (xx) untuk menyimpan ToString of the TimeSpan. Manfaat dari ini adalah ketelitian tidak harus dimasukkan ke dalam tipe data atau perhitungan, (detik vs milidetik vs hari vs Fortnights) Yang perlu Anda lakukan adalah menggunakan TimeSpan.Parse / TryParse. Inilah yang akan saya lakukan.

  2. Gunakan tanggal kedua, datetime atau set datetime, yang menyimpan hasil dari tanggal + rentang waktu pertama. Membaca dari db adalah soal TimeSpan x = SecondDate - FirstDate. Menggunakan opsi ini akan melindungi Anda untuk pustaka akses data non .NET yang mengakses data yang sama tetapi tidak memahami TimeSpans; jika Anda memiliki lingkungan seperti itu.

Rick
sumber
1
Opsi 2 terdengar seperti itu mungkin berguna setiap saat. thx
rahicks
3

Agar konsisten dengan apa yang mungkin merupakan sumber yang paling mungkin menghasilkan rentang waktu (menghitung perbedaan 2 kali atau tanggal-kali), Anda mungkin ingin menyimpan .NET TimeSpansebagai DateTimeJenis SQL Server .

Ini karena dalam SQL Server, perbedaan 2 DateTime( Castuntuk Floatdan kemudian Castkembali ke DateTime) hanyalah DateTimerelatif terhadap 1 Januari 1900. Kel. Perbedaan +0.1 detik adalah 1 Januari 1900 00: 00: 00.100 dan -0.1 detik adalah 31 Desember 1899 23: 59: 59.900.

Untuk mengonversi .NET TimeSpanke DateTimeTipe SQL Server , Anda harus terlebih dahulu mengonversinya menjadi .NET DateTimedengan menambahkannya ke DateTime1 Januari 1900. Tentu saja, ketika Anda membacanya di .NET dari SQL Server, Anda harus terlebih dahulu membacanya menjadi NET. DateTimeDan kemudian kurangi 1 Januari 1900 dari itu untuk mengubahnya menjadi NET TimeSpan.

Untuk kasus penggunaan di mana rentang waktu dihasilkan dari SQL Server DateTimedan dalam SQL Server (yaitu melalui T-SQL) dan SQL Server sebelum 2016, tergantung pada jangkauan dan kebutuhan presisi Anda, mungkin tidak praktis untuk menyimpannya sebagai milidetik (belum lagi Ticks) karena IntJenis dikembalikan oleh DateDiff(vs BigIntdari SS 2016 + 's DateDiff_Big) meluap setelah ~ 24 hari senilai milidetik dan ~ 67 tahun. detik. Sedangkan, solusi ini akan menangani rentang waktu dengan presisi hingga 0,1 detik dan dari -147 hingga +8,099 tahun.

PERINGATAN:

  1. Ini hanya akan bekerja jika perbedaannya relatif terhadap 1 Januari 1900 akan menghasilkan nilai dalam kisaran DateTimeTipe SQL Server (1 Januari 1753 hingga 31 Desember, 9999 alias -147 hingga +8.099 tahun). Kita tidak perlu terlalu khawatir di TimeSpansisi .NET , karena dapat menampung ~ 29 k hingga +29 k tahun. Saya tidak menyebutkan DateTime2Tipe SQL Server (yang jangkauannya, di sisi negatifnya, jauh lebih besar daripada SQL Server DateTime), karena: a) tidak dapat dikonversi ke numerik melalui rentang sederhana Castdan b) DateTimeharus cukup. untuk sebagian besar kasus penggunaan.

  2. DateTimePerbedaan SQL Server yang dihitung melalui metode Cast- to - Float- dan - back tampaknya tidak akurat setelah 0,1 detik.

Tom
sumber
Saya lupa saya bahkan membaca Q ini jauh lebih sedikit daripada saya menulis A ini, dan sedang mencari A lagi. Saya mulai membaca A ini dan berpikir dalam hati: (Wow, ini adalah jawaban terbaik sejauh ini!). : D
Tom
3

Ada beberapa cara bagaimana menyajikan rentang waktu dalam database.

waktu

Tipe data ini didukung sejak SQL Server 2008 dan merupakan cara yang disukai untuk menyimpan a TimeSpan. Tidak diperlukan pemetaan. Ini juga bekerja dengan baik dengan kode SQL.

public TimeSpan ValidityPeriod { get; set; }

Namun, seperti yang dinyatakan dalam pertanyaan awal, tipe data ini dibatasi hingga 24 jam.

datetimeoffset

Tipe datetimeoffsetdata peta langsung ke System.DateTimeOffset. Ini digunakan untuk mengekspresikan offset antara a datetime/ datetime2ke UTC, tetapi Anda juga dapat menggunakannya untuk TimeSpan.

Namun, karena datatype menyarankan semantik yang sangat spesifik, maka Anda juga harus mempertimbangkan opsi lain.

datetime / datetime2

Salah satu pendekatan mungkin menggunakan tipe datetimeatau datetime2. Ini terbaik dalam skenario di mana Anda perlu memproses nilai-nilai dalam database secara langsung, yaitu. untuk tampilan, prosedur tersimpan, atau laporan. Kekurangannya adalah Anda perlu mengurangi nilaiDateTime(1900,01,01,00,00,00) dari tanggal untuk mendapatkan kembali rentang waktu dalam logika bisnis Anda.

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

Pendekatan lain mungkin untuk mengubah TimeSpan menjadi tick dan menggunakan bigintdatatype. Namun, pendekatan ini memiliki kelemahan yang sulit untuk digunakan dalam query SQL.

public long ValidityPeriod { get; set; }

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

varchar (N)

Ini terbaik untuk kasus-kasus di mana nilainya harus dibaca oleh manusia. Anda juga dapat menggunakan format ini dalam kueri SQL dengan memanfaatkan CONVERT(datetime, ValidityPeriod)fungsinya. Bergantung pada presisi yang dibutuhkan, Anda akan membutuhkan antara 8 dan 25 karakter.

public string ValidityPeriod { get; set; }

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

Bonus: Periode dan Durasi

Menggunakan string, Anda juga dapat menyimpan tipe data NodaTime , terutama Durationdan Period. Yang pertama pada dasarnya sama dengan TimeSpan, sementara yang lain menghargai bahwa beberapa hari dan bulan lebih panjang atau lebih pendek dari yang lain (mis. Januari memiliki 31 hari dan Februari memiliki 28 atau 29; beberapa hari lebih panjang atau lebih pendek karena waktu musim panas) ). Dalam kasus seperti itu, menggunakan TimeSpan adalah pilihan yang salah.

Anda dapat menggunakan kode ini untuk mengonversi Periode:

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

Dan kemudian gunakan seperti

public string ValidityPeriod { get; set; }

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

Saya sangat suka NodaTime dan sering menyelamatkan saya dari bug yang rumit dan banyak sakit kepala. Kekurangannya di sini adalah Anda benar-benar tidak dapat menggunakannya dalam query SQL dan perlu melakukan perhitungan dalam memori.

Jenis yang Ditentukan Pengguna CLR

Anda juga memiliki opsi untuk menggunakan tipe data khusus dan mendukung TimeSpankelas khusus secara langsung. Lihat CLR Jenis yang Ditentukan Pengguna untuk detail.

Kelemahan di sini adalah bahwa tipe data mungkin tidak berperilaku baik dengan Laporan SQL. Juga, beberapa versi SQL Server (Azure, Linux, Data Warehouse) tidak didukung.

Konversi Nilai

Dimulai dengan EntityFramework Core 2.1, Anda memiliki opsi untuk menggunakan Konversi Nilai .

Namun, saat menggunakan ini, EF tidak akan dapat mengonversi banyak pertanyaan menjadi SQL, menyebabkan kueri berjalan di dalam memori; berpotensi mentransfer banyak dan banyak data ke aplikasi Anda.

Jadi setidaknya untuk saat ini, mungkin lebih baik tidak menggunakannya, dan hanya memetakan hasil kueri dengan Automapper .

MovGP0
sumber
1

Biasanya, saya menyimpan TimeSpan sebagai bigint yang diisi dengan kutu dari properti TimeSpan.Ticks seperti yang disarankan sebelumnya. Anda juga dapat menyimpan TimeSpan sebagai varchar (26) yang diisi dengan output TimeSpan.ToString (). Empat fungsi skalar (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks) yang saya tulis sangat membantu untuk menangani TimeSpan di sisi SQL dan menghindari peretasan yang akan menghasilkan rentang yang dibatasi secara artifisial. Jika Anda dapat menyimpan interval dalam .NET TimeSpan sama sekali, itu harus bekerja dengan fungsi-fungsi ini juga. Selain itu, fungsi memungkinkan Anda untuk bekerja dengan TimeSpans dan kutu 100-nanosecond bahkan ketika menggunakan teknologi yang tidak termasuk .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
sumber