Atau, bagaimana Microsoft memungkinkan perjalanan waktu?
Pertimbangkan kode ini:
DECLARE @Offset datetimeoffset = sysdatetimeoffset();
DECLARE @UTC datetime = getUTCdate();
DECLARE @UTCFromOffset datetime = CONVERT(datetime,SWITCHOFFSET(@Offset,0));
SELECT
Offset = @Offset,
UTC = @UTC,
UTCFromOffset = @UTCFromOffset,
TimeTravelPossible = CASE WHEN @UTC < @UTCFromOffset THEN 1 ELSE 0 END;
@Offset
diatur sebelumnya @UTC
, namun terkadang memiliki nilai nanti . (Saya sudah mencoba ini di SQL Server 2008 R2 dan SQL Server 2016. Anda harus menjalankannya beberapa kali untuk menangkap kejadian yang mencurigakan.)
Ini tampaknya bukan hanya masalah pembulatan atau kurangnya presisi. (Sebenarnya, saya pikir pembulatan adalah apa yang "memperbaiki" masalah sesekali.) Nilai-nilai untuk menjalankan sampel adalah sebagai berikut:
- Mengimbangi
- 2017-06-07 12: 01: 58.8801139 -05: 00
- UTC
- 2017-06-07 17: 01: 58.877
- UTC Dari Offset:
- 2017-06-07 17: 01: 58.880
Jadi, ketelitian datetime memungkinkan .880 sebagai nilai yang valid.
Bahkan contoh Microsoft GETUTCDATE menunjukkan nilai SYS * lebih lambat dari metode yang lebih lama, meskipun telah SELECTed sebelumnya :
SELECT 'SYSDATETIME() ', SYSDATETIME(); SELECT 'SYSDATETIMEOFFSET()', SYSDATETIMEOFFSET(); SELECT 'SYSUTCDATETIME() ', SYSUTCDATETIME(); SELECT 'CURRENT_TIMESTAMP ', CURRENT_TIMESTAMP; SELECT 'GETDATE() ', GETDATE(); SELECT 'GETUTCDATE() ', GETUTCDATE(); /* Returned: SYSDATETIME() 2007-05-03 18:34:11.9351421 SYSDATETIMEOFFSET() 2007-05-03 18:34:11.9351421 -07:00 SYSUTCDATETIME() 2007-05-04 01:34:11.9351421 CURRENT_TIMESTAMP 2007-05-03 18:34:11.933 GETDATE() 2007-05-03 18:34:11.933 GETUTCDATE() 2007-05-04 01:34:11.933 */
Saya kira ini karena mereka berasal dari sistem informasi dasar yang berbeda. Adakah yang bisa mengkonfirmasi dan memberikan rincian?
Dokumentasi SYSDATETIMEOFFSET Microsoft mengatakan "SQL Server memperoleh nilai tanggal dan waktu dengan menggunakan GetSystemTimeAsFileTime () Windows API" (terima kasih srutzky), tetapi dokumentasi GETUTCDATE mereka jauh lebih spesifik, hanya mengatakan bahwa nilai "berasal dari sistem operasi sistem komputer tempat instance dari SQL Server berjalan ".
(Ini bukan sepenuhnya akademis. Saya mengalami masalah kecil yang disebabkan oleh ini. Saya memperbarui beberapa prosedur untuk menggunakan SYSDATETIMEOFFSET alih-alih GETUTCDATE, dengan harapan untuk presisi yang lebih besar di masa mendatang, tetapi saya mulai mendapatkan pesanan aneh karena prosedur lain dilakukan masih menggunakan GETUTCDATE dan kadang-kadang "melompati" prosedur saya yang dikonversi dalam log.)
sumber
Jawaban:
Masalahnya adalah kombinasi rincian data / akurasi dan sumber nilai.
Pertama,
DATETIME
hanya akurat / terperinci untuk setiap 3 milidetik. Oleh karena itu, mengubah dari tipe data yang lebih tepat sepertiDATETIMEOFFSET
atauDATETIME2
tidak hanya membulatkan ke atas atau ke bawah ke milidetik terdekat, bisa jadi berbeda 2 milidetik.Kedua, dokumentasi tampaknya menyiratkan perbedaan dari mana nilai-nilai itu berasal. Fungsi SYS * menggunakan fungsi FileTime presisi tinggi.
Dokumentasi SYSDATETIMEOFFSET menyatakan:
sedangkan dokumentasi GETUTCDATE menyatakan:
Kemudian, dalam dokumentasi About Time , bagan menunjukkan dua (dari beberapa) jenis berikut:
Petunjuk tambahan ada dalam dokumentasi .NET untuk
StopWatch
kelas (penekanan pada huruf tebal miring):Kelas Stopwatch
Stopwatch.IsHighResolution Field
Oleh karena itu, ada "jenis" waktu yang berbeda yang memiliki presisi dan sumber yang berbeda pula.
Tetapi, bahkan jika itu adalah logika yang sangat longgar, menguji kedua jenis fungsi sebagai sumber untuk
DATETIME
nilai membuktikannya. Adaptasi kueri dari pertanyaan berikut menunjukkan perilaku ini:Pengembalian:
Seperti yang Anda lihat dalam hasil di atas, UTC dan UTC2 keduanya
DATETIME
tipe data.@UTC2
diatur melaluiSYSUTCDATETIME()
dan diatur setelah@Offset
(juga diambil dari fungsi SYS *), tetapi sebelum@UTC
yang diatur melaluiGETUTCDATE()
. Namun,@UTC2
tampaknya datang sebelumnya@UTC
. Bagian OFFSET ini sama sekali tidak terkait dengan apa pun.NAMUN, untuk bersikap adil, ini masih bukan bukti dalam arti yang ketat. @MartinSmith melacak
GETUTCDATE()
panggilan dan menemukan yang berikut:Saya melihat tiga hal menarik dalam tumpukan panggilan ini:
GetSystemTime()
yang mengembalikan nilai yang hanya tepat hingga milidetik.SYSDATETIMEOFFSET
.Ada banyak info bagus di sini mengenai berbagai jenis waktu, sumber berbeda, pergeseran, dll: Memperoleh perangko waktu resolusi tinggi .
Sungguh, tidak tepat untuk membandingkan nilai-nilai dari berbagai ketentuan. Misalnya, jika Anda memiliki
2017-06-07 12:01:58.8770011
dan2017-06-07 12:01:58.877
, lalu bagaimana Anda tahu bahwa yang memiliki presisi kurang lebih besar, kurang dari, atau sama dengan nilai dengan presisi lebih? Membandingkan mereka mengasumsikan bahwa yang kurang tepat sebenarnya2017-06-07 12:01:58.8770000
, tetapi siapa yang tahu apakah itu benar atau tidak? Waktu sebenarnya bisa berupa2017-06-07 12:01:58.8770005
atau2017-06-07 12:01:58.8770111
.Namun, jika Anda memiliki
DATETIME
tipe data, maka Anda harus menggunakan fungsi SYS * sebagai sumber karena lebih akurat, bahkan jika Anda kehilangan beberapa presisi karena nilainya dipaksa menjadi tipe yang kurang tepat. Dan sejalan dengan itu, tampaknya lebih masuk akal untuk menggunakanSYSUTCDATETIME()
daripadaSYSDATETIMEOFFSET()
hanya menelepon untuk menyesuaikannyaSWITCHOFFSET(@Offset, 0)
.sumber
GETUTCDATE
tampaknya memanggilGetSystemTime
danSYSDATETIMEOFFSET
memanggilGetSystemTimeAsFileTime
meskipun keduanya tampaknya mendidih ke hal yang sama blogs.msdn.microsoft.com/oldnewthing/20131101-00/?p=2763GetSystemTime
panggilan ituGetSystemTimeAsFileTime
, tetapi saya memang memperhatikan hal-hal menarik dalam tumpukan panggilan yang Anda posting di komentar pertanyaan: 1) ia menggunakan DateFromParts sehingga kemungkinan besar terpotong menjadi ms (lanjutan)