Graças à diversidade de culturas na Terra, temos uma variedade de formatos de data. Para datas numéricas, temos mês-dia-ano, dia-mês-ano e ano-mês-dia. Também temos formatos curtos e longos. As datas podem ser misturadas com o tempo, o que é outra história. Essa realidade nos acompanha no trabalho. É por isso que o formato de data SQL não é algo que podemos levar com calma.
Nas Filipinas, usamos 2 formatos:mês-dia-ano e dia-mês-ano. Mês-dia-ano é o formato geral para datas numéricas. Mas com formatos de data mais longos, usamos alternadamente dia-mês-ano e mês-dia-ano.
No trabalho, nunca encontrei a configuração de formato de data do SQL Server diferente de mês-dia-ano. No entanto, varia em relatórios e arquivos para trocas de dados e projeto Extract-Transform-Load (ETL). Muito menos usuários que o alteram em suas estações por preferências pessoais! Com todos esses cenários, não lidar com eles adequadamente é uma receita a ser quebrada.
Seus aplicativos lidam com diferentes culturas? Esse é outro nível de complexidade e um problema ao lidar com esses vários formatos de data SQL. Neste artigo, exploraremos o padrão para lidar com todas essas variedades e exemplos. Leia até o final! Mas antes de prosseguirmos, vamos fazer um pequeno desvio sobre como o SQL Server armazena datas.
Como o SQL Server armazena datas
Adivinhe. O SQL Server armazena 29/03/2021 21:35 como está no banco de dados? Que tal 2021-03-29? Eles são armazenados como strings formatadas? Com base nesta documentação da Microsoft, não é assim.
Vamos pegar o tipo de dados DATE, por exemplo. Ele é armazenado como um inteiro de 3 bytes.
Como nós sabemos?
Bem, a Microsoft diz que sim, mas não fornece mais informações. Isso não significa que não podemos saber com certeza. Primeiro, o valor mínimo do tipo de dados DATE é 01/01/0001 ou 1º de janeiro de 1 CE ou Era Comum. Para converter isso em um inteiro, convertemos essa data em VARBINARY primeiro, assim:
SELECT CAST(CAST('01/01/0001' AS DATE) AS VARBINARY(3))
O resultado é 0x000000 em formato hexadecimal. A partir desse valor, podemos ver que o valor inteiro de 1º de janeiro de 1 CE é 0. É lógico porque esse é o valor mínimo de DATE.
Agora, avançamos 1 dia.
SELECT CAST(CAST('01/02/0001' AS DATE) AS VARBINARY(3)) -- January 2, 1 CE
O resultado é 0x010000 . Isso é um pouco complicado, mas este post nos deu uma ideia. Não podemos tratá-lo como o vemos. Os bytes são revertidos e o valor hexadecimal real é 0x000001 . Se você sabe um pouco sobre números hexadecimais, sabe que isso é igual a 1 – é 1 dia a partir do ponto de partida, 1º de janeiro de 1 CE.
Agora, vamos tentar uma data recente:29/03/2021.
SELECT CAST(CAST('03/29/2021' AS DATE) AS VARBINARY(3))
O resultado é 0x55420B . Quando o revertemos, ele se torna 0x0B4255 . Desta vez, não podemos saber o valor olhando para ele. Então, multiplicamos por 1 como um número inteiro.
SELECT 0x0B4255 * CAST(1 AS INT)
O resultado é 737.877 . Este é o número de dias a partir de 1º de janeiro de 1 CE. Vamos verificar com DATEDIFF.
SELECT DATEDIFF(DAY,CAST('01/01/0001' AS DATE),CAST('03/29/2021' AS DATE))
O resultado é o mesmo:737.877 dias. Muito legal!
Resumindo:a data formatada é apenas para fins de apresentação
É assim que o SQL Server armazena os tipos de dados DATE. É diferente para DATETIME, SMALLDATETIME e DATETIME2, mas ainda armazenado como números inteiros. O SQL Server calcula a duração do tempo a partir do ponto de partida e exibe a data que todos podemos entender.
Esteja você olhando para o SQL Server Management Studio, dbForge Studio para SQL Server ou seu aplicativo, 29/03/2021 é apenas uma apresentação. Se você alterar a região ou o idioma, o valor armazenado 0x55420B permanecerá o mesmo.
Agora sabemos que as datas não são armazenadas como strings. Podemos esquecer de armazenar datas em um formato específico . Não é assim que funciona de qualquer maneira. Em vez disso, vamos analisar diferentes maneiras no SQL para formatar as datas que seus aplicativos precisam.
As 4 maneiras fáceis de formatar datas
Vamos examinar as seguintes funções de data SQL:
- função CONVERTER
- DEFINIR IDIOMA
- DEFINIR FORMATO DE DATA
- Função FORMATO
Você também pode usar um formatador de consulta SQL.
1. Função CONVERTER
CONVERT é uma das funções de conversão de dados que também pode servir para formatação de data. A Figura 1 mostra um exemplo.
Os dois primeiros argumentos de CONVERT são o tipo de dados de destino e o valor de data. A terceira é opcional, mas também se aplica a datas. Os valores numéricos são os estilos de formato de data SQL a serem usados durante a conversão de data para string.
Na Figura 1, o Japão usa um formato ano-mês-dia com uma barra como separador. A Alemanha usa dia-mês-ano com pontos como separadores. Grã-Bretanha e França usam a mesma sequência que a Alemanha, mas com uma barra como separador. Apenas os Estados Unidos usam mês-dia-ano com um hífen como separador.
No SQL, você também pode converter a expressão DATETIME em DATE.
Para obter uma lista completa de estilos de formato de data CONVERT no SQL, verifique esta referência da Microsoft.
2. DEFINIR IDIOMA
Essa configuração especifica o idioma aplicado à sessão. Afeta os formatos de data e mensagens do sistema. Ao definir um idioma, você também aplica implicitamente as configurações de SET DATEFORMAT (vamos resolver isso mais tarde).
Por enquanto, vamos verificar os exemplos na Figura 2. Estou alterando as configurações de idioma para lituano e depois de volta para inglês.
Observe a Figura 2. O formato de data lituano é ano-mês-dia. Sempre que tento datas diferentes, a data longa sempre inclui 'm.' antes do mês e 'd.' depois do dia. A primeira letra do mês e o nome do dia da semana também não são capitalizados. É diferente para outras configurações de idioma, mas você entendeu.
Para obter mais informações sobre SET LANGUAGE, confira esta referência da Microsoft.
3. DEFINIR FORMATO DE DATA
Essa configuração coloca a ordem do mês, dia e ano para interpretar cadeias de caracteres de data. Ele substituirá as configurações de formato de data implícitas feitas por SET LANGUAGE. Aqui está um exemplo na Figura 3.
Na Figura 3, o código usa o formato DMY ou dia-mês-ano. Nessas configurações, qualquer valor de data definido para uma variável de data deve seguir esse padrão. 30/03/2021 corresponde a este formato, mas 31/03/2021 aciona um erro porque 31 não é um mês válido.
Assim, as alterações no formato de data podem interromper seu aplicativo se a lógica operar na premissa de outro formato.
Para obter mais informações sobre SET DATEFORMAT, confira esta referência da Microsoft.
4. Função FORMATO
De todas as opções de formatação disponíveis, esta é a mais flexível. É semelhante para formatação de data em .Net, pois FORMAT depende da presença do .Net Framework no servidor onde o SQL Server está instalado. Essa é a desvantagem desta opção, no entanto.
Assim como em C#, FORMAT recebe um valor de data e uma string de formato. Vejamos alguns exemplos na Figura 4.
Assim como no .Net, no SQL Server você pode formatar datas usando diferentes separadores. Além disso, você pode posicionar o mês, dia e ano em qualquer lugar. Então, você pode obter as informações culturais e usar seu formato de data.
Para obter mais informações e exemplos sobre FORMAT, confira esta referência da Microsoft.
Agora, identificamos 4 maneiras de formatar datas e a variedade de formatos de data. Existe um formato padrão que sempre funciona ao converter strings em datas?
ISO 8601 – O formato de data SQL mais portátil e livre de erros que você pode usar para conversão
A ISO 8601 existe desde 1988. É o padrão internacional na troca de dados relacionados a datas e horas .
Também está disponível na função CONVERT como um dos estilos de formato de data:os estilos 126 e 127 são compatíveis com ISO 8601.
O que o torna portátil e livre de erros?
O problema com formatos não ISO 8601
Vamos demonstrar o problema para não ISO 8601 com um exemplo:
DECLARE @d VARCHAR(10) = '03/09/2021';
SET LANGUAGE Italian;
SELECT FORMAT(CONVERT(DATETIME, @d),'D')
SET LANGUAGE English
SELECT FORMAT(CONVERT(DATETIME, @d),'D')
SET DATEFORMAT DMY
SELECT FORMAT(CONVERT(DATETIME, @d),'D')
SET DATEFORMAT MDY
SELECT FORMAT(CONVERT(DATETIME, @d),'D')
Dependendo do local da data, você pode interpretar @d como 9 de março de 2021 ou 3 de setembro de 2021. Você não pode ter certeza de qual é qual. É aí que mora o problema.
Confira o resultado na Figura 5 abaixo:
Mesmo o SQL Server não sabe com certeza!
Pior ainda, esse tipo de cenário pode quebrar seu aplicativo exatamente como aconteceu na Figura 3 anterior. Essa situação é problemática para aplicativos que lidam com usuários multiculturais.
A ISO 8601 pode ajudar com isso?
Usando a ISO 8601 para lidar com problemas de formatação
Observe quando o formato ISO 8601 aaaaMMdd é usado em vez de MM/dd/aaaa e confira o resultado na Figura 6:
Será sempre 9 de março, independentemente das configurações de idioma e formato de data usadas. Isso é ótimo para trocas de dados e integrações de sistemas. Se o seu usuário tiver outro formato de data na estação, isso também não importará.
Se você precisar transformar suas datas em strings e vice-versa, use a ISO 8601.
ISO 8601 no SQL Server vem em 2 sabores:
- AAAAMMDD é apenas para datas.
- AAAA-MM-DDTHH:MM:SS para uma combinação de data e hora, em que T é o delimitador entre data e hora.
Outras maneiras de lidar com formatos de data de aplicativos para SQL Server
1. Use controles com reconhecimento de data no aplicativo
Quando você pedir a um usuário para inserir datas em um formulário, não permita que ele use texto livre. Use controles de data que permitem escolher apenas valores válidos.
2. Converter para um formato diferente somente quando necessário
Não fique transformando datas em strings e vice-versa. Use os tipos de dados nativos Date ou DateTime do aplicativo de chamada. Se você precisar transformá-los por qualquer motivo, use a ISO 8601.
3. Defina a data/hora, fuso horário e cultura na inicialização do aplicativo, se aplicável
Se seu aplicativo usa um formato de data fixo e seus usuários adoram ajustar os formatos de data, você pode corrigir ambos na inicialização do aplicativo. Defina explicitamente o que seu aplicativo precisa. Será muito melhor se o administrador da rede puder bloquear essas configurações.
Recomendações
Então, lidar com variedades de formato de data SQL é esmagador? Não posso culpá-lo se você ainda achar assim, mas descobrimos que não é impossível.
Aqui está o que cobrimos:
- As datas SQL são armazenadas como números inteiros . O que vemos com nossos olhos já está formatado com base nas configurações do SQL Server. Não importa quantas vezes mudemos o idioma e os formatos de data, o valor armazenado permanecerá o mesmo. É inútil pensar em armazenar datas em um formato específico.
- Existem 4 maneiras de formatar datas:CONVERTER , DEFINIR IDIOMA , DEFINIR FORMATO DE DATA e FORMATAR .
- Se você precisar transformar datas em strings e vice-versa, use o formato ISO 8601 .
- Existem 3 outras maneiras de lidar com formatos de data:
- usando controles com reconhecimento de data em seu aplicativo;
- transformando datas em strings somente quando necessário;
- definindo o fuso horário necessário, cultura, data/hora do servidor na inicialização, quando aplicável .
Você acha que isso será útil para você e para os outros? Então, por favor, compartilhe este artigo em suas plataformas de mídia social favoritas.