Este artigo explora as principais diferenças entre o datetime2 e pequena data e hora tipos de dados no SQL Server.
Ambos os tipos de dados são usados para armazenar valores de data e hora, no entanto, existem algumas diferenças importantes entre os dois. Na maioria dos casos, é melhor usar datetime2 (A Microsoft também recomenda isso), no entanto, pode haver alguns cenários em que você precise usar smalldatetime .
Aqui está uma tabela que descreve as principais diferenças entre esses dois tipos.
Recurso | smalldatetime | datahora2 |
---|---|---|
Compatível com SQL (ANSI e ISO 8601) | Não | Sim |
Período | 1900-01-01 a 2079-06-06 | 0001-01-01 a 9999-12-31 |
Intervalo de tempo | 00:00:00 até 23:59:59 | 00:00:00 até 23:59:59.9999999 |
Comprimento do caractere | máximo de 19 posições | 19 posições no mínimo 27 no máximo |
Tamanho do armazenamento | 4 bytes, fixo | 6 a 8 bytes, dependendo da precisão* * Mais 1 byte para armazenar a precisão |
Precisão | Um minuto | 100 nanossegundos |
Precisão de segundo fracionário | Não | Sim |
Precisão de segundo fracionário definida pelo usuário | Não | Sim |
Deslocamento de fuso horário | Nenhum | Nenhum |
Reconhecimento e preservação de deslocamento de fuso horário | Não | Não |
Conhece o horário de verão | Não | Não |
Vantagens de 'datetime2'
Conforme visto na tabela acima, o datetime2 type tem muitas vantagens sobre smalldatetime , Incluindo:
- maior intervalo de datas
- precisão de segundos fracionários
- precisão opcional especificada pelo usuário
- maior precisão
- se alinha com os padrões SQL (ANSI e ISO 8601)
* Em alguns casos, um datetime2 value usa um byte extra para armazenar a precisão, no entanto, quando armazenada em um banco de dados, a precisão é incluída na definição da coluna, portanto, o valor armazenado real não requer o byte extra.
Devo usar 'datetime' ou 'smalldatetime'?
A Microsoft recomenda datetime2 para novos trabalhos (e pelos mesmos motivos listados acima).
Portanto, você deve usar datetime2 , a menos que você tenha um motivo específico para não fazê-lo (como trabalhar com um sistema legado).
Exemplo 1 – Comparação básica
Aqui está um exemplo rápido para demonstrar a diferença básica entre datetime2 e pequena data e hora .
DECLARE @thedatetime2 datetime2(7), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30.5555555'; SET @thesmalldatetime = @thedatetime2; SELECT @thedatetime2 AS 'datetime2', @thesmalldatetime AS 'smalldatetime';
Resultado:
+-----------------------------+---------------------+ | datetime2 | smalldatetime | |-----------------------------+---------------------| | 2025-05-21 10:15:30.5555555 | 2025-05-21 10:16:00 | +-----------------------------+---------------------+
Aqui, defino uma pequena data e hora variável para o mesmo valor que datetime2 variável. Isso faz com que o valor seja convertido em smalldatetime e podemos então usar um
SELECT
para ver o valor de cada variável. Nesse caso, o datetime2 variável usa uma escala de 7, o que significa que tem 7 casas decimais. A pequena data e hora valor, por outro lado, não tem nenhum casas decimais. Além disso, seus segundos são definidos como zero e seus minutos são arredondados para cima.
Isso é esperado, porque a documentação oficial da Microsoft afirma que
smalldatetime
A hora de 's é baseada em um dia de 24 horas, com segundos sempre zero (:00) e sem segundos fracionários.
Assim, podemos ver que o datetime2 type fornece um valor de data/hora muito mais preciso e preciso.
Claro, você pode não precisar de todos esses segundos fracionários. Uma das coisas boas de datetime2 é que você pode especificar quantos (se houver) segundos fracionários você deseja.
Exemplo 2 – Usando menos casas decimais
Neste exemplo, reduzo o datetime2 escala para 0:
DECLARE @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30.5555555'; SET @thesmalldatetime = @thedatetime2; SELECT @thedatetime2 AS 'datetime2', @thesmalldatetime AS 'smalldatetime';
Resultado:
+---------------------+---------------------+ | datetime2 | smalldatetime | |---------------------+---------------------| | 2025-05-21 10:15:31 | 2025-05-21 10:16:00 | +---------------------+---------------------+
Nesse caso, o datetime2 valor não inclui mais uma parte fracionária. Ambos os tipos agora compartilham o mesmo comprimento de caractere (19 posições).
Mas ainda há diferenças.
O datetime2 value honra o valor dos segundos, embora neste caso seus segundos tenham sido arredondados para cima. Conforme mencionado, a pequena data e hora o componente de segundos do valor é sempre definido como zero e, neste caso, seus minutos foram arredondados.
O motivo do datetime2 segundos é arredondado é porque a parte fracionária é 5 ou superior. Se reduzirmos a parte fracionária, nenhum arredondamento é realizado:
DECLARE @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30.4444444'; SET @thesmalldatetime = @thedatetime2; SELECT @thedatetime2 AS 'datetime2', @thesmalldatetime AS 'smalldatetime';
Resultado:
+---------------------+---------------------+ | datetime2 | smalldatetime | |---------------------+---------------------| | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 | +---------------------+---------------------+
No entanto, o smalldatetime os minutos do valor continuam sendo arredondados para cima.
Exemplo 3 – Definindo valores de literais de string
Nos exemplos anteriores, o smalldatime o valor foi atribuído definindo-o com o mesmo valor que datetime2 valor. Quando fazemos isso, o SQL Server realiza uma conversão implícita para que os dados “se ajustem” ao novo tipo de dados.
No entanto, se tentarmos atribuir esse mesmo literal de string ao smalldatetime variável, obtemos um erro:
DECLARE @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime SET @thedatetime2 = '2025-05-21 10:15:30.4444444' SET @thesmalldatetime = '2025-05-21 10:15:30.4444444' SELECT @thedatetime2 AS 'datetime2', @thesmalldatetime AS 'smalldatetime';
Resultado:
Msg 295, Level 16, State 3, Line 5 Conversion failed when converting character string to smalldatetime data type.
Isso porque smalldatetime aceita apenas literais de string com 3 ou menos segundos fracionários.
Você pode esperar que ele não aceite literais de string com qualquer segundos fracionários, visto que não inclui segundos fracionários, mas não é o caso. Aceita felizmente 3 segundos fracionários, mas não mais.
Então, para superar esse problema, precisamos reduzir a parte fracionária para apenas 3 (ou menos) casas decimais.
DECLARE @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30.4444444'; SET @thesmalldatetime = '2025-05-21 10:15:30.444'; SELECT @thedatetime2 AS 'datetime2', @thesmalldatetime AS 'smalldatetime';
Resultado:
+---------------------+---------------------+ | datetime2 | smalldatetime | |---------------------+---------------------| | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 | +---------------------+---------------------+
O datetime2 type não tem essa limitação, mesmo usando uma escala de 0.
Exemplo 4 – Tamanho de armazenamento
A pequena data e hora tipo de dados tem um tamanho de armazenamento fixo de 4 bytes. Este é um dos poucos benefícios smalldatetime tem mais de datetime2 .
O datetime2 pode ser de 6, 7 ou 8 bytes, dependendo de sua precisão. Portanto, um datetime2 value sempre usará pelo menos 2 bytes a mais de armazenamento do que um smalldatetime valor.
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 .
No entanto, isso provavelmente 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 @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30'; SET @thesmalldatetime = @thedatetime2; SELECT DATALENGTH(@thedatetime2) AS 'datetime2', DATALENGTH(@thesmalldatetime) AS 'smalldatetime';
Resultado
+-------------+-----------------+ | datetime2 | smalldatetime | |-------------+-----------------| | 6 | 4 | +-------------+-----------------+
Mas se os convertermos em varbinary , obtemos o seguinte:
DECLARE @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30'; SET @thesmalldatetime = @thedatetime2; SELECT DATALENGTH(CAST(@thedatetime2 AS varbinary(10))) AS 'datetime2', DATALENGTH(CAST(@thesmalldatetime AS varbinary(10))) AS 'smalldatetime';
Resultado
+-------------+-----------------+ | datetime2 | smalldatetime | |-------------+-----------------| | 7 | 4 | +-------------+-----------------+
Então datetime2 usa um byte extra quando convertido em varbinary . Muitos desenvolvedores supõem que a conversão para varbinary é representativo de como o SQL Server realmente armazena valores de data e hora.
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.
O exemplo a seguir demonstra isso. Mostra que quando os dados são armazenados em uma coluna de banco de dados, obtemos um comprimento de 6 bytes para datetime2 vs 4 bytes para smalldatetime .
Exemplo 5 – Tamanho de armazenamento para dados armazenados
Neste exemplo, crio um banco de dados e uso
COL_LENGTH
para retornar o comprimento de cada coluna, em bytes. Em seguida, insiro um datetime2 e pequena data e hora valor nele e use DBCC PAGE()
para encontrar o comprimento dos dados reais no arquivo de paginação. Isso nos mostra o espaço de armazenamento que cada tipo de dados usa quando armazenado em um banco de dados. Crie um banco de dados:
CREATE DATABASE CompareTypes;
Crie uma tabela:
USE CompareTypes; CREATE TABLE Datetime2vsSmalldatetime ( TheDateTime2 datetime2(0), TheSmallDateTime smalldatetime );
Nesse caso, crio duas colunas - uma é datetime2(0) coluna e a outra é um smalldatetime coluna.
Verifique o comprimento da coluna
Verifique o comprimento (em bytes) de cada coluna:
SELECT COL_LENGTH ( 'dbo.Datetime2vsSmalldatetime' , 'TheDateTime2' ) AS 'datetime2', COL_LENGTH ( 'dbo.Datetime2vsSmalldatetime' , 'TheSmallDateTime' ) AS 'smalldatetime';
Resultado:
+-------------+-----------------+ | datetime2 | smalldatetime | |-------------+-----------------| | 6 | 4 | +-------------+-----------------+
Assim, vemos que o datetime2(0) coluna tem um comprimento de 6 bytes, em comparação com smalldatetime comprimento de 4 bytes.
Inserir dados
Agora vamos ver o tamanho do armazenamento dos valores reais de data e hora quando eles são armazenados no SQL Server. Podemos usar
DBCC PAGE()
para inspecionar a página real no arquivo de dados. Mas primeiro, precisamos inserir dados em nossas colunas.
Inserir dados:
DECLARE @thedatetime2 datetime2 = '2025-05-21 10:15:30'; INSERT INTO Datetime2vsSmalldatetime ( TheSmallDateTime, TheDateTime2 ) SELECT @thedatetime2, @thedatetime2;
Selecione os dados (só para conferir):
SELECT * FROM Datetime2vsSmalldatetime;
Resultado:
+---------------------+---------------------+ | TheDateTime2 | TheSmallDateTime | |---------------------+---------------------| | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 | +---------------------+---------------------+
Usando DBCC PAGE()
Aqui é onde usamos
DBCC PAGE()
para inspecionar a página real no arquivo de dados. Primeiro, usaremos
DBCC IND()
para encontrar o PagePID:DBCC IND('CompareTypes', 'dbo.Datetime2vsSmalldatetime', 0);
Resultado (usando saída vertical):
-[ RECORD 1 ]------------------------- PageFID | 1 PagePID | 308 IAMFID | NULL IAMPID | NULL ObjectID | 1205579333 IndexID | 0 PartitionNumber | 1 PartitionID | 72057594043039744 iam_chain_type | In-row data PageType | 10 IndexLevel | NULL NextPageFID | 0 NextPagePID | 0 PrevPageFID | 0 PrevPagePID | 0 -[ RECORD 2 ]------------------------- PageFID | 1 PagePID | 344 IAMFID | 1 IAMPID | 308 ObjectID | 1205579333 IndexID | 0 PartitionNumber | 1 PartitionID | 72057594043039744 iam_chain_type | In-row data PageType | 1 IndexLevel | 0 NextPageFID | 0 NextPagePID | 0 PrevPageFID | 0 PrevPagePID | 0
Isso retorna dois registros. Estamos interessados no PageType de 1 (o segundo registro). Queremos o PagePID desse registro. Nesse caso, o PagePID é 344 .
Agora podemos pegar esse PagePID e usá-lo da seguinte forma:
DBCC TRACEON(3604, -1); DBCC PAGE(CompareTypes, 1, 344, 3);
Isso produz muitos dados, mas estamos interessados principalmente na seguinte parte:
Slot 0 Column 1 Offset 0x4 Length 6 Length (physical) 6 TheDateTime2 = 2025-05-21 10:15:30 Slot 0 Column 2 Offset 0xa Length 4 Length (physical) 4 TheSmallDateTime = 2025-05-21 10:16:00.000
Isso mostra que smalldatetime tem um comprimento de 4 bytes e datetime2(0) tem 6 bytes quando armazenado em um banco de dados.
Portanto, neste caso, há apenas uma diferença de 2 bytes, mas datetime2(0) é mais preciso e segue os padrões ANSI e ISO 8601.