1. SQL Server, Datas e Horas

Ao converter uma string para data, o SQL não apresentou o mesmo horário
Post 1/3. Este post é parte da série: SQL Server: Esclarecendo Datas e Horas
Tempo de leitura estimado: 8 minutos

Tempo é uma coisa interessante. Dias, anos, horas, minutos, milissegundos… Em algum momento de sua vida com banco de dados você precisou, ou vai precisar, trabalhar com tempo. Datas e horas nos permitem realizar métricas, organizar compromissos, etc., e a maioria dos sistemas hoje em dia necessitam manipular data e hora.

O SQL Server fornece um amplo suporte para que você possa não só armazenar, mas realizar diversas operações como somar, ou subtrair, horas, dias, segundos, anos, ordenar e comparar data e hora! Porém, existe uma série de mitos e confusões relacionados a este assunto. Por exemplo, você é capaz de explicar o porquê isso acontece?

Ao converter uma string para data, o SQL não apresentou o mesmo horário

Ao converter uma string para data, o SQL não apresentou o mesmo horário

O objetivo deste post é esclarecer como manipular datas dentro de seus scripts T-SQL.  Iremos abordar os seguintes assuntos:

  1. Representando datas
  2. Formatando a exibição
  3. Tipos de dados de data

Por hoje, vamos focar na representação das datas, isto é, o modo como o SQL Server entende as datas que enviamos para ele.

Formato de Datas

Vamos começar falando do formato. Existe uma enorme confusão neste assunto. Primeiro, vamos deixar uma coisa bem clara: existem as datas que sua aplicação envia para o SQL Server, via código T-SQL, e as datas que o SQL Server envia para a sua aplicação. São duas coisas diferentes.

Fornecendo Datas para o SQL Server

Quando você envia um código T-SQL para o SQL Server, quem na verdade envia é uma aplicação. A aplicação é o que chamamos de client (por conta da arquitetura client-server).  Tudo que um client faz é pegar um código T-SQL, que não passa de texto (string), entregar ao SQL Server para ele processar, e esperar a resposta. Quando o client precisa fornecer uma data ao SQL Server ela vai junto com o código TSQL, como texto puro também.

Esta data que vai no código é o que podemos chamar de “formato de entrada“. Especificar uma data no SQL Server é muito simples: basta colocar a bendita entre aspas simples (‘). Isso mesmo jovem, você especifica datas igual especifica uma string qualquer dentro da linguagem T-SQL. O SQL Server só vai entender que aquilo é uma data, e não uma string qualquer, se ela for convertida para um tipo de dados de data, como por exemplo datetimetimedatedatetime2, etc. Essa conversão pode ser explícita ou implícita:

  • Implícitas
    • Quando atribui para uma variável do tipo data
    • Quando atribui para uma coluna do tipo data
    • Quando compara com alguma expressão do tipo data
  • Explícitas
    • Quando converte usando CAST ou CONVERT para um tipo de data
       

Apesar do SQL Server parecer bem flexível quanto ao formato de entrada, você não pode colocar qualquer coisa. Não é a casa da mãe Joana não! Ao converter sua string para uma data, o SQL Server vai validar o formato e se não estiver em conformidade você irá receber um erro dizendo que não foi possível converter uma data a partir de uma string.

SQL Server Error 241

Este é o erro que você irá ver com mais frequência quando estiver trabalhando com datas e o formato estiver errado.

Essa string que contém uma data, que você coloca no código SQL, é chamada de Literal (ou constante) de data e pode ser interpretado de várias formas.  Aqui na documentação você tem todos os detalhes. O formato mais comum de um literal de data no SQL Server é:

Formato Geral de Literal de Datas

 

A primeira coisa é entender os separadores. Basicamente, uma data é composta de várias partes: dia, mês, ano, hora, minutos, segundos e milissegundos. O SQL Server suporta barra (/), o ponto (.) e o traço como separadores para a parte dos dias. Para a parte das horas somente os dois-pontos (:) podem ser usados para separar horas, minutos e segundos. E somente o ponto pode ser usado para separar milissegundos. Todas as datas a seguir são válidas:

Se você especificar um separador diferente destes mencionados acima,  vai dar erro…

Msg 241, Level 16, State 1, Line 1
Conversion failed when converting date and/or time from character string.
Msg 242, Level 16, State 3, Line 1
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.

Você pode omitir certas partes da data. Quando faz isso, o SQL Server considera a parte omitida como 0 (zero).  Se omitir a parte das horas, isto é, especificar somente dia, mês e ano, o horário será o mesmo que 00:00:00.000, isto é, meia noite em ponto! O horário tem de ser especificado no formato “HH:mm:SS.Milissegundos [AM|PM]“. Veja alguns exemplos:

O tipo “datetime” permite que você especifique até 3 casas nos milissegundos. Os tipos time e datetime2 permitem até 7 casas! Depois falamos mais sobre os diferentes tipos de dados de data e hora. Por agora, concentre-se no formato. Outra  coisa interessante é que você pode especificar o formato 12 horas (AM/PM) nas horas!

O SQL Server não é idiota, portanto não tente um 13 da manhã…

Curiosamente, isso é inválido e gera erro (omitir toda a parte do horário, exceto as horas):

Porém, se você especifica AM ou PM…

Usar separadores de datas força o SQL Server a levar em consideração a região. Isto é, quando você usa um separador na parte dos dias, o SQL Server irá levar em consideração, por exemplo, o formato Brasil (dd/MM/AAAA) ou EUA (MM/dd/AAAA). A data abaixo pode ser 02 de fevereiro ou 01 de janeiro, dependendo de como o SQL Server está interpretando:

SET DATEFORMAT não é pra exibição!E é aqui onde entra o comando SET DATEFORMAT. Este comando é muito polêmico. A maioria dos desenvolvedores acha que ele irá alterar a forma como a data é exibida. Pegadinha! Este comando apenas diz para o SQL Server como ele deve considerar o formato das datas de ENTRADA. Ele é a maneira de você dizer “SQL Server, estou te enviando as datas neste formato“.   Para saber qual o valor atual do dateformat, você pode executar este SELECT:

O DATEFORMAT diz ao SQL Server onde está o dia, o mês, e o ano em sua data. Cada sessão possui seu dateformat, e não afeta o dateformat de outras sessões.

O DATEFORMAT padrão é definido quando você se conecta e é baseado nas configurações de idioma do login que você usa pra se conectar. Nós podemos alterar o DATEFORMAT a qualquer momento:

Lembre-se que o SET DATEFORMAT só irá afetar aquela sessão em que está se executando o comando. Quando você se desconectar (ou sua aplicação) do SQL Server, ou mesmo abrir outra sessão, o dateformat será baseado nas configurações do Login usado para a conexão.

Este aqui irá gerar erro, pois, conforme o dateformat configurado, não existe um 01 do 13…

Se você alterar o dateformat, deverá alterar o formato de suas datas:

No caso do ano, se você especificar o ano com 4 dígitos, o SQL Server detecta onde o ano está. Neste caso o dateformat vai valer somente para a posição do dia e do mês:

Sim, isso é um saco! Felizmente você pode contornar isso apenas deixando de usar os separadores. Sim, meu caro, quando não se usa separadores o SQL Server interpreta a sua data usando o formato ISO 8601 que é um formato padrão, independente do buraco do mundo onde você esteja!  Este formato sempre irá considerar AnoMêsDia ou AAAA/MM/DD ou AA/MM/DD. Sempre! Sempre! Independente do DATEFORMAT!

E você pode continuar especificando as horas normalmente, já que é sempre o mesmo formato, independente da região:

Eu gosto muito deste formato e sempre estou usando nos meus scripts. Mas você deve tomar muito cuidado pra não cometer alguns errinhos:

Fique atento ao tipos de dados também…

 

Bom, para deixar você respirar um pouco, vou encerrar por aqui. Na próxima semana posto a continuação! Fique ligado no blog!

 

[]’s

 

 

Navegue na série 2. SQL Server, Datas e Horas: Exibição e Conversões >>
Compartilhe este post!

Comments ( 2 )

  1. / ReplyRenato Siqueira
    Curti o post, Rodrigo! Bem explicado e recheado de exemplos nada distantes do dia-a-dia. Leitura obrigatória pra quem trabalha direto com T-SQL. []'s

Leave a Reply to Renato Siqueira Cancel reply