2. SQL Server, Datas e Horas: Exibição e Conversões

Post 2/3. Este post é parte da série: SQL Server: Esclarecendo Datas e Horas
Tempo de leitura estimado: 6 minutos

Olá! No último post, focamos em como o SQL Server entende as datas que enviamos no código T-SQL. Para resumir: Especificar datas no SQL Server é como especificar uma string qualquer, porém com um formato específico. Você pode usar o DATEFORMAT para auxiliar na interpretação do SQL Server (e não como a data é exibida) ou usar formatos genéricos, como o ISO. Bom, agora vamos falar sobre a exibição das datas, ou seja, o formato de saída!

Vamos começar alinhando um ponto: O SQL Server não exibe nada! Ele entrega data à alguma aplicação (algum driver de conexão como jTDS, ODBC,OLEDB, etc.). Internamente, uma data é bem diferente do formato como especificamos. A data não é armazenada como texto. É um formato binário bem diferente: imagine que seja um número muito louco que de alguma forma contenha os dias, meses, anos, hora, etc. (prometo um post sobre isso em breve). Ao efetuar um SELECT que retorne uma coluna com algum, por exemplo, datetime, o SQL Server não entrega uma string para a aplicação. Ele entrega este número (binário). A aplicação é responsável por interpretar este valor e exibi-lo da forma correta, ou seja, a aplicação também entende onde está o dia, mês, ano e horário nesse número. (O excel também trabalha de forma parecida. Experimente digitar este valor 42071,1588859 e formatar a célula como data…)

No caso do Management Studio (SSMS), quando você visualiza os resultado em um GRID (padrão), ele vai exibir as datas no formato ‘YYYY-MM-AA HH:MM:SS.mmm’. Dependendo do tipo de dado (date, time, datetime2, etc.) ele vai omitir a data ou o horário. Perceba (execute no SSMS):

A questão aqui é: a aplicação é a verdadeira responsável por exibir a data em um formato mais apropriado.

Caso você não queria que a aplicação faça estre trabalho você pode forçar o SQL Server a entregar uma data como uma string, ao invés deste número binário maluco… Em outras palavras, você pode converter uma data para uma string. Bom aqui cabe deixar uma coisa clara: quando você converte uma data para string, aquela data perde seus poderes mágicos: comparar com outras datas, adicionar datas, subtrair, ordenar. A data convertida passa a ser tratada como texto puro e perde certos comportamentos exclusivos de data. Se sua aplicação não vai precisar realizar nenhum processamento extra com aquela data e se o seu objetivo é apenas exibição, então não há problemas! Observe os exemplos a seguir para entender melhor. Para converter uma data para string você usa a função CONVERT. Ela permite que você especifique um parâmetro especial chamado Style (A função CAST também pode ser usada, mas não permite especificar o Style). O Style é um número pré-determinado que faz com que o resultado da conversão saia em um formato específico. A sintaxe geral é:

CONVERT(varchar(tamanho),  ValorData, Style)

Primeiro, você deve estar atento ao tamanho da string (pode ser varchar ou char) que irá receber o resultado. Se o seu objetivo é converter a data para o formato dd/MM/AAAA então você vai precisar de 2 caracteres para o dia, 2 para o mês, 4 para o ano e mais 2 para as barras, totalizando 10 caracteres. Mas se você quiser incluir as horas e minutos (dd/MM/AAAA HH:MM) então, além dos 10, você vai precisar de 1 para espaço, 2 para as horas, 1 para os dois-pontos e 2 para os minutos, isto é, mais 6 caracteres, o que faz necessário 16 caracteres para a data inteira. Então fique atento a isso para colocar o tamanho correto, ou você irá ver sua data cortada… O Style é um valor fixo e pré-determinado que você pode encontrar aqui na documentação desta função. ValorData pode ser qualquer coisa que seja uma data. Em outras palavras, ValorData pode ser qualquer expressão que resulte em um tipo de data: funções de sistema (DATEADD,CURRENT_TIMESTAMP, etc.), funções de usuário, nomes de variável, nomes de colunas, etc. Bom,  a documentação é sua melhor fonte. Este site também contém uma série de exemplos de uso da função e irá te ajudar quando precisar de uma resposta rápida. No mais, alguns exemplos:

Uma coisa interessante é que podemos notar o que foi falado aqui com o uso do comando DBCC OUTPUTBUFFER. Basicamente, este comando nos permite ver os dados que uma determinada sessão entregou para a aplicação. Execute esta query:

Agora abra outra sessão e execute o comando DBCC OUTPUTBUFFER, passando como parâmetro o número da sessão onde a query anterior foi executada (no meu caso, foi 51):

Você deverá um resultado parecido com este (irei manter somente o início, que é o relevante pra nós neste momento):

00000040 04 f0 00 36 00 d1 0d 00 41 4e 54 45 53 5f 44 41 .ð.6.Ñ..ANTES_DA
00000050 5f 44 41 54 41 0a 00 32 38 2f 30 33 2f 32 30 31 _DATA..28/03/201
00000060 35 0e 00 44 45 50 4f 49 53 5f 44 41 5f 44 41 54 5..DEPOIS_DA_DAT
00000070 41 fd 11 00 c1 00 01 00 00 00 00 00 00 00 81 03 Aý..Á………..
00000080 00 00 00 00 00 20 00 a7 0d 00 09 04 f0 00 36 00 ….. .§.. .ð.6.
00000090 00 00 00 00 21 00 6f 08 00 00 00 00 00 20 00 a7 ….!.o…… .§
000000a0 0e 00 09 04 f0 00 36 00 d1 0d 00 41 4e 54 45 53 .. .ð.6.Ñ..ANTES
000000b0 5f 44 41 5f 44 41 54 41 08 69 a4 00 00 d9 73 0e _DA_DATA.i¤..Ùs.
000000c0 01 0e 00 44 45 50 4f 49 53 5f 44 41 5f 44 41 54 DEPOIS_DA_DAT

Primeiro, repare no trecho em verde. Este é o trecho que corresponde ao primeiro SELECT, onde nós usamos um CONVERT para converter a data para texto. Perceba que o valor retornado é realmente um texto puro, e por isso podemos visualizar facilmente os caracteres correspondentes. Agora, repare o trecho em azul. Este trecho corresponde ao segundo SELECT, onde nós retornamos a data pura. Notou!? Cadê a data? Ela está ali, só que está sendo entregue em um formato binário, cujo seus bytes não são equivalentes aos digitos e barras, conforme no trecho anterior. O trecho em binário que corresponde à data está marcado em laranja, apenas por curiosidade (no post que eu prometi sobre data, eu darei mais detalhes 🙂 ).

Para finalizar esta parte, um último ponto: Os poderes mágicos da data. Uma das grandes vantagens em ter tipos de dados que trabalhem exclusivamente com datas é a facilidade que temos em lidar com operações aritméticas envolvendo datas, como por exemplo, somar dias, meses, horas, minutos e segundo. Assim, o SQL Server é quem se preocupa em fazer todas as verificações quando, por exemplo, você adiciona 1 minuto à data “28/02/2016 23:59:59.003”.  Ordenar datas também é um diferencial: Por exemplo, considere as datas ’10/02/2015′ e ’01/03/2015′. Claramente, se eu te pedisse para ordenar estas datas de forma crescente, você, uma pessoa muito esperta, me diria assim:

’10/02/2015′
’01/03/2015′

Que está correto! O SQL Server também faria exatamente a mesma coisa, se estes valores estiverem sendo trabalhados como data… Agora olha só o que acontece quando você converte para texto e ordena pelo resultado da conversão:

Aqui, os resultados:

OrdenadoPorData
2015-02-10 00:00:00.000
2015-03-01 00:00:00.000

OrdenadoPorTexto
2015-03-01 00:00:00.000
2015-02-10 00:00:00.000

Repare que no segundo SELECT, a data de março veio ANTES da data de fevereiro, em um ORDER BY crescente 😯 ! Será um bug? Nada disso. Quando você converteu para texto e ordenou pelo resultado em texto, as regras de ordenação mudaram, pois para texto são diferentes das regras para data.  Veja:

Resultados:

OrdenadoPorTexto        Convertido
2015-03-01 00:00:00.000 01/03/2015
2015-02-10 00:00:00.000 10/02/2015

O motivo é simples:  A string ’01/03/2015′ começa com ‘0’ (dígito zero), que conforme as regras de ordenação de texto (onde envolve collations e outras coisas) é menor do que ‘1’.

Entendeu o porquê deve-se tomar cuidado com as conversões de data para texto? No próximo post, último desta série, vamos falar sobre os tipos de dados… Aproveitando o gancho, você saberia explicar o porquê disto?

 

Se não, aguarde o próximo post (Que tentarei publicar na semana que vem).

[]’s
Navegue na série << 1. SQL Server, Datas e Horas3. SQL Server, Datas e Horas: Tipos de dados >>
Compartilhe este post!

Comments ( 2 )

  1. / ReplyFabricio Lima
    Bacana o post. Ainda não tinha usado o comando: DBCC OUTPUTBUFFER(X) Obrigado por compartilhar.
    • / ReplyRodrigo Ribeiro Gomes
      Fala Fabrício! Muito obrigado. O DBCC OUTPUTBUFFER além de ser útil em casos bem extremos, ele é documentando o que dá mais confiança. Além de usar para demonstrar este tipo de coisa e validar certas teorias, ele pode ser útil para ver possíveis erros enviados por uma sessão, por exemplo. É um comando que depende de nossa criatividade. Abraços.

Leave a Reply to Fabricio Lima Cancel reply