Sinon, comment Microsoft a-t-il rendu possible le voyage dans le temps?
Considérez ce 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
est défini avant @UTC
, mais il a parfois une valeur ultérieure . (J'ai essayé cela sur SQL Server 2008 R2 et SQL Server 2016. Vous devez l'exécuter plusieurs fois pour détecter les occurrences suspectes.)
Cela ne semble pas être simplement une question d'arrondi ou de manque de précision. (En fait, je pense que l'arrondi est ce qui "résout" le problème de temps en temps.) Les valeurs pour un exemple d'exécution sont les suivantes:
- Décalage
- 2017-06-07 12: 01: 58.8801139 -05: 00
- UTC
- 2017-06-07 17: 01: 58.877
- UTC à partir du décalage:
- 2017-06-07 17: 01: 58.880
La précision datetime autorise donc le .880 comme valeur valide.
Même les exemples GETUTCDATE de Microsoft montrent que les valeurs SYS * sont plus récentes que les anciennes méthodes, bien qu'elles aient été sélectionnées plus tôt :
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 */
Je suppose que c'est parce qu'ils proviennent de différentes informations système sous-jacentes. Quelqu'un peut-il confirmer et fournir des détails?
La documentation SYSDATETIMEOFFSET de Microsoft indique que "SQL Server obtient les valeurs de date et d'heure en utilisant l'API Windows GetSystemTimeAsFileTime ()" (merci srutzky), mais leur documentation GETUTCDATE est beaucoup moins spécifique, indiquant seulement que la "valeur est dérivée du système d'exploitation de la ordinateur sur lequel s'exécute l'instance de SQL Server ".
(Ce n'est pas entièrement académique. J'ai rencontré un problème mineur causé par cela. J'étais en train de mettre à niveau certaines procédures pour utiliser SYSDATETIMEOFFSET au lieu de GETUTCDATE, dans l'espoir d'une plus grande précision à l'avenir, mais j'ai commencé à obtenir des commandes étranges parce que d'autres procédures étaient toujours en utilisant GETUTCDATE et parfois "sauter en avant" de mes procédures converties dans les journaux.)
la source
Réponses:
Le problème est une combinaison de granularité / précision du type de données et de la source des valeurs.
Tout d'abord, il
DATETIME
n'est précis / granulaire que toutes les 3 millisecondes. Par conséquent, la conversion à partir d'un type de données plus précis, tel queDATETIMEOFFSET
ouDATETIME2
ne sera pas simplement arrondi à la milliseconde la plus proche, pourrait être différente de 2 millisecondes.Deuxièmement, la documentation semble impliquer une différence dans la provenance des valeurs. Les fonctions SYS * utilisent les fonctions FileTime de haute précision.
La documentation SYSDATETIMEOFFSET indique:
tandis que la documentation GETUTCDATE indique:
Ensuite, dans la documentation À propos de l'heure , un graphique présente les deux (parmi plusieurs) types suivants:
Des indices supplémentaires sont dans la documentation .NET pour la
StopWatch
classe (accentuation en gras italique le mien):Classe chronomètre
Chronomètre.IsHighResolution Field
Par conséquent, il existe différents «types» de temps qui ont à la fois des précisions et des sources différentes.
Mais, même si c'est une logique très lâche, tester les deux types de fonctions comme sources de la
DATETIME
valeur le prouve. L'adaptation suivante de la requête de la question montre ce comportement:Retour:
Comme vous pouvez le voir dans les résultats ci-dessus, UTC et UTC2 sont tous deux des
DATETIME
types de données.@UTC2
est défini viaSYSUTCDATETIME()
et est défini après@Offset
(également tiré d'une fonction SYS *), mais avant@UTC
lequel est défini viaGETUTCDATE()
. Pourtant,@UTC2
semble venir avant@UTC
. La partie OFFSET de tout cela n'a aucun rapport avec quoi que ce soit.CEPENDANT, pour être juste, ce n'est toujours pas une preuve au sens strict. @MartinSmith a retracé l'
GETUTCDATE()
appel et a trouvé ce qui suit:Je vois trois choses intéressantes dans cette pile d'appels:
GetSystemTime()
auquel renvoie une valeur qui n'est précise que jusqu'aux millisecondes.SYSDATETIMEOFFSET
.Il y a beaucoup de bonnes informations ici concernant les différents types de temps, les différentes sources, la dérive, etc.: Acquérir des horodatages haute résolution .
En réalité, il n'est pas approprié de comparer les valeurs de différentes précisions. Par exemple, si vous avez
2017-06-07 12:01:58.8770011
et2017-06-07 12:01:58.877
, alors comment savez-vous que celui avec moins de précision est supérieur, inférieur ou égal à la valeur avec plus de précision? Les comparer suppose que le moins précis est en fait2017-06-07 12:01:58.8770000
, mais qui sait si c'est vrai ou non? Le temps réel aurait pu être soit2017-06-07 12:01:58.8770005
ou2017-06-07 12:01:58.8770111
.Cependant, si vous avez des
DATETIME
types de données, vous devez utiliser les fonctions SYS * comme source car elles sont plus précises, même si vous perdez une certaine précision car la valeur est forcée dans un type moins précis. Et dans ce sens, il semble plus logique d'utiliserSYSUTCDATETIME()
plutôt que d'appelerSYSDATETIMEOFFSET()
uniquement pour l'ajuster viaSWITCHOFFSET(@Offset, 0)
.la source
GETUTCDATE
semble appelerGetSystemTime
etSYSDATETIMEOFFSET
appelleGetSystemTimeAsFileTime
bien que les deux se résument apparemment à la même chose blogs.msdn.microsoft.com/oldnewthing/20131101-00/?p=2763GetSystemTime
appelsGetSystemTimeAsFileTime
, mais j'ai remarqué des choses intéressantes dans la pile d'appels que vous avez postée dans le commentaire de la question: 1) il utilise DateFromParts donc très probablement tronqué en ms (suite)