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

datetime vs datetimeoffset no SQL Server:qual é a diferença?


Este artigo destaca as principais diferenças entre o datetime 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. Mas há diferenças significativas entre os dois.

Talvez a diferença mais óbvia seja que o datetimeoffset armazena o deslocamento de fuso horário, enquanto datetime não.

Outra diferença importante é que datetimeoffset permite especificar a precisão (até 7 casas decimais). Isso significa que datetimeoffset os valores podem variar em seu tamanho de armazenamento, dependendo da precisão que está sendo usada.

O datahora Por outro lado, tem um tamanho de armazenamento fixo e precisão.



Geralmente, você deve evitar usar datetime a menos que você tenha um bom motivo para usá-lo (como dar suporte a um sistema legado). Além disso, o datetime2 tipo é uma correspondência mais próxima de datetimeoffset , então é melhor usar isso se não precisar de um deslocamento de fuso horário.

De qualquer forma, aqui está uma tabela que compara datetime e deslocamento de data e hora :
Recurso deslocamento de data e hora datahora
Compatível com SQL (ANSI e ISO 8601) Sim Não
Período 0001-01-01 a 9999-12-31 1753-01-01 a 9999-12-31
Intervalo de tempo 00:00:00 até 23:59:59.9999999 00:00:00 até 23:59:59.997
Comprimento do caractere mínimo de 26 posições
máximo de 34
mínimo de 19 posições
máximo de 23
Tamanho do armazenamento 8 a 10 bytes, dependendo da precisão*

* Mais 1 byte para armazenar a precisão em alguns casos. Veja abaixo mais informações.
8 bytes
Precisão 100 nanossegundos Arredondado para incrementos de 0,000, 0,003 ou 0,007 segundos
Precisão de segundo fracionário definida pelo usuário Sim Não
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

Exemplo 1 – Comparação básica


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

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

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

Nesse caso, o deslocamento de data e hora O valor inclui o deslocamento do fuso horário e 7 casas decimais. O datahora value, por outro lado, não inclui o deslocamento de fuso horário e possui apenas 3 casas decimais. Além disso, seu terceiro dígito fracionário é arredondado para cima. Isso ocorre porque sua precisão é sempre arredondada para incrementos de 0,000, 0,003 ou 0,007 segundos.

Exemplo 2 – Definindo valores de literais de string


No exemplo anterior, o datetime 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.

Se tentarmos atribuir o mesmo valor diretamente ao datetime variável, obtemos um erro:
DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.5555555 +07:30';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Resultado:
Msg 241, Level 16, State 1, Line 5
Conversion failed when converting date and/or time from character string.

Isso ocorre porque o datetime tipo de dados não oferece suporte a um literal de string com um deslocamento de fuso horário. Além disso, ele não suporta literais de string com mais de 3 casas decimais.

Portanto, se removermos o deslocamento de fuso horário, mas mantivermos todos os segundos fracionários, ainda receberemos um erro:
DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.5555555';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Resultado:
Msg 241, Level 16, State 1, Line 5
Conversion failed when converting date and/or time from character string.

Para que funcione, precisaríamos atribuir um valor com no máximo 3 casas decimais:
DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.555';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

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

De qualquer forma, datetime sempre terá um valor diferente para datetimeoffset , porque não inclui o deslocamento do fuso horário. Isso será verdade mesmo se usarmos a mesma precisão de segundos fracionários e o mesmo valor de segundos fracionários.

Para demonstrar isso, veja o que acontece se atribuirmos o mesmo valor a datetimeoffset :
DECLARE 
  @thedatetimeoffset datetimeoffset(3), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.123';
SET @thedatetime = '2025-05-21 10:15:30.123';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Resultado:
+------------------------------------+-------------------------+
| datetimeoffset                     | datetime                |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.1230000 +00:00 | 2025-05-21 10:15:30.123 |
+------------------------------------+-------------------------+

Neste caso datetimeoffset usa uma escala de 3, que dá 3 casas decimais (o mesmo que datetime ). Isso é feito usando datetimeoffset(3) ao declarar a variável.

Também alterei os segundos fracionários para que datetime não os arredondaria (para que ambos os valores compartilhem exatamente a mesma parte fracionária).

Independentemente disso, deslocamento de data e hora ainda adiciona um deslocamento de fuso horário, definido para seu valor padrão de +00:00.

Observe que meu sistema exibe zeros à direita em datetimeoffset parte fracionária de, mas o valor usa apenas 3 casas decimais.

Exemplo 3 - Tamanho de armazenamento


O datahora tipo de dados usa 8 bytes.

O deslocamento de data e hora tipo de dados usa 8, 9 ou 10 bytes, dependendo de sua precisão.

Portanto, você não está salvando nenhum tamanho de armazenamento usando datetime .

No entanto, se você converter um offset de data e hora valor a uma constante binária, ele adiciona 1 byte para armazenar a precisão.

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), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = @thedatetimeoffset;
SELECT 
  DATALENGTH(@thedatetimeoffset) AS 'datetimeoffset',
  DATALENGTH(@thedatetime) AS 'datetime';

Resultado
+------------------+------------+
| datetimeoffset   | datetime   |
|------------------+------------|
| 10               | 8          |
+------------------+------------+

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

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

Resultado
+------------------+------------+
| datetimeoffset   | datetime   |
|------------------+------------|
| 11               | 8          |
+------------------+------------+

Um byte extra é adicionado ao datetimeoffset valor, mas não para o datetime valor. Isso ocorre porque o offset de data e hora value precisa de um byte extra para armazenar a precisão (porque a precisão é definida pelo usuário). O datahora value por outro lado tem uma precisão fixa, então não há necessidade de que a precisão seja armazenada com o valor.

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 não inclui a precisão ao armazenar datetimeoffset valores. Isso ocorre porque a precisão está incluída na definição da coluna.

Para obter mais detalhes sobre como esse tipo de dados é armazenado no banco de dados, consulte Noções básicas sobre o tamanho de armazenamento 'datetimeoffset' no SQL Server.

Devo usar 'datetime' ou 'datetimeoffset'?


Se você precisar incluir um deslocamento de fuso horário, precisará usar datetimeoffset . Caso contrário, datetime pode ser suficiente.

No entanto, a Microsoft recomenda que você use datetime2 para novos trabalhos, pois tem muitos benefícios em relação a datetime .

Consulte datetime vs datetime2 para obter uma comparação desses tipos de dados.