Wie hat Microsoft alternativ Zeitreisen ermöglicht?
Betrachten Sie diesen Code:
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
ist vorher eingestellt @UTC
, hat aber manchmal einen späteren Wert. (Ich habe dies unter SQL Server 2008 R2 und SQL Server 2016 versucht. Sie müssen es einige Male ausführen, um die verdächtigen Vorkommen zu erkennen.)
Dies scheint nicht nur eine Frage der Rundung oder der Ungenauigkeit zu sein. (Tatsächlich denke ich, dass die Rundung das Problem gelegentlich "behebt".) Die Werte für einen Probelauf lauten wie folgt:
- Offset
- 2017-06-07 12: 01: 58.8801139 -05: 00
- koordinierte Weltzeit
- 2017-06-07 17: 01: 58.877
- UTC vom Versatz:
- 2017-06-07 17: 01: 58.880
Die Datums- / Uhrzeitgenauigkeit erlaubt also die .880 als gültigen Wert.
Selbst die GETUTCDATE-Beispiele von Microsoft zeigen, dass die SYS * -Werte später als die älteren Methoden sind, obwohl sie zuvor ausgewählt wurden :
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 */
Ich nehme an, das liegt daran, dass sie aus verschiedenen zugrunde liegenden Systeminformationen stammen. Kann jemand Details bestätigen und angeben?
In der SYSDATETIMEOFFSET-Dokumentation von Microsoft heißt es: "SQL Server ermittelt die Datums- und Zeitwerte mithilfe der Windows-API GetSystemTimeAsFileTime ()" (danke srutzky). Die GETUTCDATE-Dokumentation ist jedoch viel weniger spezifisch und besagt nur, dass der Wert vom Betriebssystem des Betriebssystems abgeleitet ist Computer, auf dem die Instanz von SQL Server ausgeführt wird ".
(Dies ist nicht ganz akademisch. Ich bin auf ein kleines Problem gestoßen, das dadurch verursacht wurde. Ich habe einige Verfahren aktualisiert, um SYSDATETIMEOFFSET anstelle von GETUTCDATE zu verwenden, in der Hoffnung auf eine größere Präzision in der Zukunft, aber ich bekam merkwürdige Bestellungen, weil andere Verfahren dies waren Ich benutze immer noch GETUTCDATE und "springe" gelegentlich meinen konvertierten Prozeduren in den Protokollen voraus.)
quelle
Antworten:
Das Problem ist eine Kombination aus Granularität / Genauigkeit des Datentyps und Quelle der Werte.
Erstens
DATETIME
ist nur alle 3 Millisekunden genau / granular. Daher von einem genaueren Datentyp wie die UmwandlungDATETIMEOFFSET
oderDATETIME2
wird nicht gleich um nach oben oder unten auf die nächste Millisekunde, könnte es 2 Millisekunden unterschiedlich sein.Zweitens scheint die Dokumentation einen Unterschied darin zu implizieren, woher die Werte stammen. Die SYS * -Funktionen verwenden die hochpräzisen FileTime-Funktionen.
In der Dokumentation zu SYSDATETIMEOFFSET heißt es:
In der GETUTCDATE- Dokumentation heißt es:
In der About Time- Dokumentation zeigt ein Diagramm die folgenden zwei (von mehreren) Typen:
Weitere Hinweise finden Sie in der .NET-Dokumentation für die
StopWatch
Klasse (Hervorhebung in Fettdruck kursiv):Stoppuhr-Klasse
Stopwatch.IsHighResolution Field
Daher gibt es verschiedene "Arten" von Zeiten, die sowohl unterschiedliche Präzisionen als auch unterschiedliche Quellen haben.
Aber selbst wenn dies eine sehr lockere Logik ist,
DATETIME
beweist das Testen beider Arten von Funktionen als Quellen für den Wert dies. Die folgende Anpassung der Abfrage aus der Frage zeigt dieses Verhalten:Kehrt zurück:
Wie Sie in den obigen Ergebnissen sehen können, sind UTC und UTC2 beide
DATETIME
Datentypen.@UTC2
wird über gesetztSYSUTCDATETIME()
und wird danach gesetzt@Offset
(auch aus einer SYS * -Funktion entnommen), aber davor@UTC
wird via gesetztGETUTCDATE()
. Doch@UTC2
scheint vorher zu kommen@UTC
. Der OFFSET-Teil davon hat nichts mit irgendetwas zu tun.Um fair zu sein, ist dies jedoch immer noch kein Beweis im engeren Sinne. @MartinSmith verfolgte den
GETUTCDATE()
Anruf und fand Folgendes:Ich sehe drei interessante Dinge in diesem Aufrufstapel:
GetSystemTime()
der einen Wert zurückgibt, der nur auf die Millisekunden genau ist.SYSDATETIMEOFFSET
.Hier gibt es viele gute Informationen zu den verschiedenen Arten von Zeit, verschiedenen Quellen, Drift usw .: Erfassen von hochauflösenden Zeitstempeln .
Es ist wirklich nicht angebracht, Werte verschiedener Präzisionen zu vergleichen. Zum Beispiel, wenn Sie haben
2017-06-07 12:01:58.8770011
und2017-06-07 12:01:58.877
dann wie Sie wissen, dass das eine mit weniger Präzision größer als, kleiner als oder mit mehr Präzision auf den Wert gleich? Wenn man sie vergleicht, wird davon ausgegangen, dass die weniger genaue tatsächlich ist2017-06-07 12:01:58.8770000
, aber wer weiß, ob das wahr ist oder nicht? Die Echtzeit könnte entweder2017-06-07 12:01:58.8770005
oder gewesen sein2017-06-07 12:01:58.8770111
.Wenn Sie jedoch
DATETIME
Datentypen haben, sollten Sie die SYS * -Funktionen als Quelle verwenden, da diese genauer sind, auch wenn Sie an Genauigkeit verlieren, da der Wert in einen weniger präzisen Typ gezwungen wird. In diesem Sinne scheint es sinnvoller zu sein, zu verwenden,SYSUTCDATETIME()
alsSYSDATETIMEOFFSET()
nur aufzurufen , um es über anzupassenSWITCHOFFSET(@Offset, 0)
.quelle
GETUTCDATE
scheint zu rufenGetSystemTime
undSYSDATETIMEOFFSET
AnrufeGetSystemTimeAsFileTime
obwohl beide offenbar auf die gleiche Sache einkochen blogs.msdn.microsoft.com/oldnewthing/20131101-00/?p=2763GetSystemTime
Anrufe nicht beweisen / widerlegenGetSystemTimeAsFileTime
, aber ich habe interessante Dinge in dem Aufrufstapel bemerkt, den Sie im Fragekommentar gepostet haben: 1) Es verwendet DateFromParts, also höchstwahrscheinlich abgeschnitten in ms (cont)