Como alternativa, como a Microsoft tornou possível a viagem no tempo?
Considere este código:
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
é definido antes @UTC
de , mas às vezes tem um valor posterior . (Eu tentei isso no SQL Server 2008 R2 e no SQL Server 2016. Você precisa executá-lo algumas vezes para capturar as ocorrências suspeitas.)
Isso não parece ser simplesmente uma questão de arredondamento ou falta de precisão. (Na verdade, acho que o arredondamento é o que "conserta" o problema ocasionalmente.) Os valores para uma execução de amostra são os seguintes:
- Desvio
- 07-06-2017 12:01:58.8801139 -05:00
- UTC
- 07-06-2017 17:01:58.877
- UTC do deslocamento:
- 07-06-2017 17:01:58.880
Portanto, a precisão de data e hora permite o .880 como um valor válido.
Mesmo os exemplos GETUTCDATE da Microsoft mostram os valores SYS* sendo posteriores aos métodos mais antigos, apesar de terem sido SELECTed antes :
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 */
Presumo que isso seja porque eles vêm de diferentes informações do sistema subjacente. Alguém pode confirmar e dar detalhes?
A documentação SYSDATETIMEOFFSET da Microsoft diz que "o SQL Server obtém os valores de data e hora usando a API do Windows GetSystemTimeAsFileTime()" (obrigado srutzky), mas sua documentação GETUTCDATE é muito menos específica, dizendo apenas que o "valor é derivado do sistema operacional do computador no qual a instância do SQL Server está sendo executada".
(Isso não é totalmente acadêmico. Encontrei um pequeno problema causado por isso. Eu estava atualizando alguns procedimentos para usar SYSDATETIMEOFFSET em vez de GETUTCDATE, na esperança de maior precisão no futuro, mas comecei a obter pedidos estranhos porque outros procedimentos foram ainda usando GETUTCDATE e ocasionalmente "saltando à frente" dos meus procedimentos convertidos nos logs.)
O problema é uma combinação de granularidade/precisão de tipo de dados e origem dos valores.
Primeiro,
DATETIME
é apenas preciso/granular a cada 3 milissegundos. Portanto, converter de um tipo de dados mais preciso, comoDATETIMEOFFSET
ouDATETIME2
não apenas arredondar para cima ou para baixo para o milissegundo mais próximo, pode ser 2 milissegundos diferente.Em segundo lugar, a documentação parece implicar uma diferença de onde os valores vêm. As funções SYS* usam as funções FileTime de alta precisão.
A documentação do SYSDATETIMEOFFSET afirma:
enquanto a documentação GETUTCDATE afirma:
Em seguida, na documentação About Time , um gráfico mostra os dois (entre vários) tipos a seguir:
Pistas adicionais estão na documentação .NET para a
StopWatch
classe (ênfase em negrito itálico minha):Classe de cronômetro
Campo Cronômetro.IsHighResolution
Portanto, existem diferentes "tipos" de tempos que têm diferentes precisões e diferentes fontes.
Mas, mesmo que seja uma lógica muito vaga, testar os dois tipos de funções como fontes para o
DATETIME
valor prova isso. A seguinte adaptação da consulta da pergunta mostra esse comportamento:Devoluções:
Como você pode ver nos resultados acima, UTC e UTC2 são ambos
DATETIME
tipos de dados.@UTC2
é definido viaSYSUTCDATETIME()
e é definido após@Offset
(também obtido de uma função SYS*), mas antes do@UTC
qual é definido viaGETUTCDATE()
. No entanto,@UTC2
parece vir antes@UTC
. A parte OFFSET disso não tem relação com nada.NO ENTANTO, para ser justo, isso ainda não é uma prova em sentido estrito. @MartinSmith rastreou a
GETUTCDATE()
chamada e encontrou o seguinte:Eu vejo três coisas interessantes nesta pilha de chamadas:
GetSystemTime()
qual retorna um valor que é preciso apenas em milissegundos.SYSDATETIMEOFFSET
.Há muitas informações boas aqui sobre os diferentes tipos de tempo, fontes diferentes, desvio, etc: Adquirir carimbos de tempo de alta resolução .
Realmente, não é apropriado comparar valores de diferentes precisões. Por exemplo, se você tem
2017-06-07 12:01:58.8770011
e2017-06-07 12:01:58.877
, como você sabe que aquele com menos precisão é maior, menor ou igual ao valor com mais precisão? Compará-los pressupõe que o menos preciso é realmente2017-06-07 12:01:58.8770000
, mas quem sabe se isso é verdade ou não? O tempo real poderia ter sido2017-06-07 12:01:58.8770005
ou2017-06-07 12:01:58.8770111
.No entanto, se você tiver
DATETIME
tipos de dados, deverá usar as funções SYS* como fonte, pois elas são mais precisas, mesmo se você perder alguma precisão, pois o valor é forçado a um tipo menos preciso. E nesse sentido, parece fazer mais sentido usarSYSUTCDATETIME()
em vez de chamarSYSDATETIMEOFFSET()
apenas para ajustá-lo viaSWITCHOFFSET(@Offset, 0)
.