Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

datetime2 vs datetimeoffset no SQL Server:Qual é a diferença?


Este artigo analisa as principais diferenças entre o datetime2 e deslocamento de data e hora tipos de dados no SQL Server.

Ambos os tipos de dados são usados ​​para armazenar valores de data e hora. Ambos são muito semelhantes, mas com uma diferença fundamental; o deslocamento de data e hora armazena o deslocamento de fuso horário.

Isso também resulta em datetimeoffset usando mais espaço de armazenamento do que datetime2 , então você só usaria datetimeoffset se você precisar do deslocamento de fuso horário.



Aqui está uma tabela que descreve as principais diferenças entre esses dois tipos.
Recurso deslocamento de data e hora datahora2
Compatível com SQL (ANSI e ISO 8601) Sim Sim
Período 0001-01-01 a 9999-12-31 0001-01-01 a 9999-12-31
Intervalo de tempo 00:00:00 até 23:59:59.9999999 00:00:00 até 23:59:59.9999999
Comprimento do caractere mínimo de 26 posições
máximo de 34
19 posições no mínimo
27 no máximo
Tamanho do armazenamento 8 a 10 bytes, dependendo da precisão*

* Mais 1 byte para armazenar a precisão
6 a 8 bytes, dependendo da precisão*

* Mais 1 byte para armazenar a precisão
Precisão 100 nanossegundos 100 nanossegundos
Precisão de segundo fracionário Sim Sim
Precisão de segundo fracionário definida pelo usuário Sim Sim
Intervalo de deslocamento de fuso horário -14:00 até +14:00 Nenhum
Reconhecimento e preservação de deslocamento de fuso horário Sim Não
Conhece o horário de verão Não Não

Devo usar 'datetime2' ou 'datetimeoffset'?


Isso depende se você precisa ou não incluir um deslocamento de fuso horário.

Se você precisar incluir um deslocamento de fuso horário, precisará usar datetimeoffset .

Caso contrário, use datetime2 , pois você economizará espaço de armazenamento e eliminará possíveis problemas com um deslocamento de fuso horário (potencialmente errado) em seus dados.

Exemplo 1 – Comparação básica


Aqui está um exemplo rápido para demonstrar a diferença básica entre datetime2 e deslocamento de data e hora .
DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime2 datetime2(7);
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime2 = @thedatetimeoffset;
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime2 AS 'datetime2';

Resultado:
+------------------------------------+-----------------------------+
| datetimeoffset                     | datetime2                   |
|------------------------------------+-----------------------------|
| 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.5555555 |
+------------------------------------+-----------------------------+

Aqui, defino um datetime2 variável para o mesmo valor que o datetimeoffset variável. Isso faz com que o valor seja convertido em datetime2 e podemos então usar um SELECT para ver o valor de cada variável.

Ambas as variáveis ​​usam uma escala de 7, o que significa que elas têm 7 casas decimais.

Portanto, neste caso, a única diferença entre os dois é que o datetimeoffset o valor inclui o deslocamento do fuso horário e o datetime2 valor não.

Exemplo 2 – Alteração da precisão


Ambos os tipos permitem especificar uma precisão (usando uma escala entre 0 e 7). Portanto, é possível definir o datetime2 valor para uma precisão menor do que o datetimeoffset valor (e vice-versa).

Exemplo:
DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime2 datetime2(3);
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime2 = @thedatetimeoffset;
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime2 AS 'datetime2';

Resultado:
+------------------------------------+-------------------------+
| datetimeoffset                     | datetime2               |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.556 |
+------------------------------------+-------------------------+

Aqui eu defino o datetime2 valor para uma escala de 3, o que significa que termina com 3 casas decimais em vez de 7. Nesse caso, seus segundos fracionários são arredondados para cima (porque o próximo dígito fracionário é 5 ou superior).

Assim, podemos ver que é possível obter um valor de data/hora diferente dependendo dos segundos fracionários que atribuímos a datetime2 . Isso também funciona no sentido inverso (por exemplo, se convertermos de datetime2(7) para datetimeoffset(3) ).

No entanto, se reduzirmos a parte fracionária, nenhum arredondamento é realizado:
DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime2 datetime2(3);
SET @thedatetimeoffset = '2025-05-21 10:15:30.5554444 +07:30';
SET @thedatetime2 = @thedatetimeoffset;
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime2 AS 'datetime2';

Resultado:
+------------------------------------+-------------------------+
| datetimeoffset                     | datetime2               |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5554444 +07:30 | 2025-05-21 10:15:30.555 |
+------------------------------------+-------------------------+

Exemplo 3 – Definindo valores de literais de string


Nos exemplos anteriores, o datetime2 valor foi atribuído definindo-o com o mesmo valor que o datetimeoffset valor. Quando fazemos isso, o SQL Server realiza uma conversão implícita para que os dados “se ajustem” ao novo tipo de dados.

Também podemos atribuir o mesmo valor diretamente ao datetime2 variável (mesmo que a documentação oficial não declare explicitamente que aceita uma string literal com um deslocamento de fuso horário):
DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime2 datetime2(7);
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime2 = '2025-05-21 10:15:30.5555555 +07:30';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime2 AS 'datetime2';

Resultado:
+------------------------------------+-----------------------------+
| datetimeoffset                     | datetime2                   |
|------------------------------------+-----------------------------|
| 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.5555555 |
+------------------------------------+-----------------------------+

Exemplo 4 – Tamanho de armazenamento


O datetime2 tipo de dados usa dois bytes a menos de armazenamento do que datetimeoffset para qualquer precisão.

O datetime2 pode ser de 6, 7 ou 8 bytes, dependendo de sua precisão.

O deslocamento de data e hora pode ser de 8, 9 ou 10 bytes, dependendo de sua precisão.

A Microsoft afirma que o datetime2 type também usa 1 byte extra para armazenar sua precisão, caso em que usaria pelo menos 3 bytes a mais que smalldatetime .

Isso também se aplica a datetimeoffset (mesmo que não seja explicitamente declarado na documentação da Microsoft).

No entanto, isso depende se estamos armazenando em uma tabela ou em uma variável e se estamos convertendo ou não em uma constante binária.

Aqui está o que acontece se usarmos o DATALENGTH() função para retornar o número de bytes usados ​​para cada um dos nossos valores:
DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime2 datetime2(7);
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime2 = @thedatetimeoffset;
SELECT 
  DATALENGTH(@thedatetimeoffset) AS 'datetimeoffset',
  DATALENGTH(@thedatetime2) AS 'datetime2';

Resultado
+------------------+-------------+
| datetimeoffset   | datetime2   |
|------------------+-------------|
| 10               | 8           |
+------------------+-------------+

Como esperado, 10 bytes para datetimeoffset e 8 bytes para datetime2 .

Mas se os convertermos em varbinary , obtemos o seguinte:
DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime2 datetime2(7);
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime2 = @thedatetimeoffset;
SELECT 
  DATALENGTH(CAST(@thedatetimeoffset AS varbinary(16))) AS 'datetimeoffset',
  DATALENGTH(CAST(@thedatetime2 AS varbinary(16))) AS 'datetime2';

Resultado
+------------------+-------------+
| datetimeoffset   | datetime2   |
|------------------+-------------|
| 11               | 9           |
+------------------+-------------+

Um byte extra é adicionado a cada valor para armazenar a precisão.

Muitos desenvolvedores supõem que a conversão para varbinary é representativo de como o SQL Server realmente armazena valores de data e hora. No entanto, isso é apenas parcialmente verdade.

Embora seja verdade que o SQL Server armazena seus valores de data e hora em hexadecimal, esse valor hexadecimal na verdade não inclui a precisão. Isso ocorre porque a precisão está incluída na definição da coluna. Mas quando convertemos para varbinary como fizemos no exemplo anterior, a precisão é prefixada e isso adiciona um byte extra.

Para obter mais detalhes sobre como esses tipos de dados são armazenados em diferentes contextos, consulte os seguintes artigos:
  • Compreendendo o tamanho do armazenamento de 'datetimeoffset' no SQL Server
  • Compreendendo o tamanho do armazenamento 'datetime2' no SQL Server