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
, mas às vezes possui um valor posterior . (Tentei isso no SQL Server 2008 R2 e no SQL Server 2016. Você deve executá-lo algumas vezes para detectar 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 "corrige" o problema ocasionalmente). Os valores para uma execução de amostra são os seguintes:
- Deslocamento
- 2017-06-07 12: 01: 58.8801139 -05: 00
- UTC
- 2017-06-07 17: 01: 58.877
- UTC do deslocamento:
- 2017-06-07 17: 01: 58.880
Portanto, a precisão de data e hora permite o .880 como um valor válido.
Até os exemplos GETUTCDATE da Microsoft mostram que os valores SYS * são posteriores aos métodos mais antigos, apesar de terem sido selecionados anteriormente :
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 ocorre porque eles vêm de diferentes informações subjacentes do sistema. Alguém pode confirmar e fornecer detalhes?
A documentação SYSDATETIMEOFFSET da Microsoft diz "O SQL Server obtém os valores de data e hora usando a API do Windows GetSystemTimeAsFileTime ()" (obrigado srutzky), mas a 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 problema menor causado por isso. Eu estava atualizando alguns procedimentos para usar SYSDATETIMEOFFSET em vez de GETUTCDATE, na esperança de obter maior precisão no futuro, mas comecei a receber pedidos estranhos porque outros procedimentos eram ainda usando GETUTCDATE e ocasionalmente "pulando à frente" dos meus procedimentos convertidos nos logs.)
fonte
Respostas:
O problema é uma combinação de granularidade / precisão do tipo de dados e origem dos valores.
Primeiro,
DATETIME
é preciso / granular apenas a cada 3 milissegundos. Assim, a conversão de um tipo de dados mais precisos, comoDATETIMEOFFSET
ouDATETIME2
não vai apenas arredondar para cima ou para baixo para o milissegundo mais próximo, poderia ser 2 milissegundos diferente.Segundo, a documentação parece implicar uma diferença na origem dos valores. As funções SYS * usam as funções FileTime de alta precisão.
A documentação do SYSDATETIMEOFFSET indica:
enquanto a documentação GETUTCDATE indica:
Em seguida, na documentação Sobre o tempo , um gráfico mostra os dois (de vários) tipos a seguir:
Pistas adicionais estão na documentação do .NET para a
StopWatch
classe (ênfase em negrito e itálico):Classe do cronômetro
Campo Stopwatch.IsHighResolution
Portanto, existem diferentes "tipos" de tempos que possuem precisão e fontes diferentes.
Mas, mesmo que essa 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 depois@Offset
(também extraído 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 nenhuma relação com nada.No entanto, para ser justo, isso ainda não é prova em sentido estrito. O @MartinSmith rastreou a
GETUTCDATE()
chamada e encontrou o seguinte:Vejo três coisas interessantes nessa pilha de chamadas:
GetSystemTime()
qual retorna um valor que é preciso apenas até os milissegundos.SYSDATETIMEOFFSET
.Há muitas informações boas aqui sobre os diferentes tipos de horário, fontes diferentes, desvio, etc.: Adquirir carimbos de data e hora de alta resolução .
Realmente, não é apropriado comparar valores de diferentes precisões. Por exemplo, se você possui
2017-06-07 12:01:58.8770011
e2017-06-07 12:01:58.877
, como você sabe que aquele com menos precisão é maior que, menor que ou igual ao valor com mais precisão? Compará-los pressupõe que o menos preciso seja realmente2017-06-07 12:01:58.8770000
, mas quem sabe se isso é verdade ou não? O tempo real poderia ter sido um2017-06-07 12:01:58.8770005
ou outro2017-06-07 12:01:58.8770111
.No entanto, se você tiver
DATETIME
tipos de dados, use as funções SYS * como origem, 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()
do que ligarSYSDATETIMEOFFSET()
apenas para ajustá-lo viaSWITCHOFFSET(@Offset, 0)
.fonte
GETUTCDATE
parece chamarGetSystemTime
eSYSDATETIMEOFFSET
chamadasGetSystemTimeAsFileTime
embora ambos aparentemente resumem à mesma coisa blogs.msdn.microsoft.com/oldnewthing/20131101-00/?p=2763GetSystemTime
as chamadasGetSystemTimeAsFileTime
, mas eu notei que coisas interessantes na pilha de chamadas que você postou o comentário pergunta: 1) ele usa DateFromParts então provavelmente truncado em ms (cont)