top of page

Trabalhando com datas no SQL Server

  • Foto do escritor: Amanda Nascimento
    Amanda Nascimento
  • 29 de mai.
  • 9 min de leitura

Atualizado: 22 de jul.


O tratamento de datas é uma parte essencial do dia a dia de quem trabalha com banco de dados no SQL Server. Seja para filtrar registros por período, calcular diferenças entre datas ou formatar resultados, entender como lidar com tipos de dados de data é fundamental.





Boas práticas com datas no SQL Server


✅ Armazene datas no formato ISO (yyyy-MM-dd) para evitar ambiguidades.

✅ Sempre use parâmetros em procedimentos armazenados para evitar problemas com formatação de data.

✅ Não use FORMAT() em filtros (piora a performance).

✅ Para intervalos, use >= e < em vez de BETWEEN com DATETIME.



Filtrar registros por datas


-- Registros de um único dia

 

SELECT * FROM pedidos

WHERE data_pedido = '2024-05-29';

 

 

-- Registros de um intervalo de datas

 

SELECT * FROM pedidos

WHERE data_pedido BETWEEN '2024-05-01' AND '2024-05-31';

Cuidado com o uso de BETWEEN em campos DATETIME, pois ele considera horas! Para incluir o dia final por completo, use:


-- Incluir o dia 2024-05-31 inteiro

WHERE data_pedido >= '2024-05-01' AND data_pedido < '2024-06-01'



Comando SET format dmy


 

SET DATEFORMAT dmy;

GO


Quando você usa o comando SET DATEFORMAT dmy; no início do script, você está configurando o SQL Server para interpretar as datas no formato dia/mês/ano durante toda a sessão (ou até que outro SET DATEFORMAT seja aplicado).


Como isso funciona no seu script:

  1. SET DATEFORMAT dmy; define que as strings de data devem ser lidas como DD/MM/YYYY.

  2. Isso evita erros de interpretação quando você insere datas como '25/12/2023' (25 de dezembro), que em um formato mdy (padrão em alguns sistemas) seria interpretado erroneamente como 12 de dezembro (ou até causar um erro).



✅ Vantagens:


  • Você não precisa ficar convertendo datas manualmente (CONVERT(DATE, ... , 103)).

  • Padroniza a interpretação de datas em todo o script.


⚠️ Cuidados:

  • Essa configuração só vale para a sessão atual (se desconectar e reconectar, volta ao padrão do servidor).

  • Se o script for executado em um ambiente com configuração diferente (mdy ou ymd), pode causar inconsistências.

  • Em alguns casos (como em bancos internacionais), é melhor usar formato explícito ISO (YYYYMMDD) ou CONVERT()/PARSE() para evitar ambiguidades.




 Retornar data e hora


FORMAT(GETDATE(), 'dd/MM/yyyy HH:mm:ss') AS 'DATA_RELATORIO'

 

FORMAT(GETDATE(), 'HH:mm:ss') AS 'HORA_ATUAL'


 Formatando datas para exibição


A função CONVERT() tem a seguinte sintaxe:


CONVERT(tipo_de_dado, expressão, estilo)


Para datas, usaremos: CONVERT(VARCHAR, GETDATE(), estilo)


 

SELECT 

    GETDATE() AS data_original,

    CONVERT(VARCHAR, GETDATE(), 105) AS formato_italiano,

    CONVERT(VARCHAR, GETDATE(), 103) AS formato_brasileiro,

    CONVERT(VARCHAR, GETDATE(), 120) AS formato_iso



O FORMAT() também formata datas com flexibilidade, mas é mais lento do que CONVERT() e deve ser evitado em consultas com muitas linhas, em grandes volumes de dados.

Exemplo:

 

DATE(), 'dd/MM/yyyy')


-- Converte a data para string em formato brasileiro

Formatando data

SELECT FORMAT(GETDATE(), 'dd/MM/yyyy') AS DataBR;

SELECT FORMAT(GETDATE(), 'dddd', 'pt-BR') AS DiaSemana;

Formatando data e hora

SELECT FORMAT(GETDATE(), 'dd/MM/yyyy HH:mm') AS DataHora;

-- Resultado: '01/06/2025 14:45'



Para exportações ou comparações com outros sistemas, os estilos 120 ou 121 (ISO 8601) são os mais recomendados.

Estilo

Resultado

Descrição

0

May 29 2025 3:45PM

Sem segundos

1

05/29/25

EUA (2 dígitos)

2

25.05.29

ANSI padrão

3

########

Europa (DD/MM/YY)

4

29.05.25

Europa com ponto

5

########

Europa com hífen

6

########

Abrev. mês em texto

7

May 29, 25

EUA com vírgula

8

15:45:12

Apenas hora

9

May 29 2025 3:45:12:123PM

Inglês detalhado

10

05-29-25

EUA com hífen

11

########

Invertido

12

250529

Compacto

13

29 May 2025 15:45:12:123

Europa com hora

14

15:45:12:123

Hora com milissegundos

20

########

ISO 8601 padrão

21

2025-05-29 15:45:12.123

ISO com milissegundos

22

05/29/25 3:45:12 PM

EUA com hora

23

########

ISO (somente data)

24

15:45:12

Somente hora (24h)

25

2025-05-29 15:45:12.123

ISO completo

100

May 29 2025 3:45PM

Igual ao estilo 0

101

05/29/2025

EUA completo

102

20250529

Compacto ISO

103

########

Brasil / Reino Unido

104

29.05.2025

Alemanha

105

########

Itália

106

29 May 2025

Abreviado

107

May 29, 2025

EUA com vírgula

108

15:45:12

Apenas hora

109

May 29 2025 3:45:12:123PM

Inglês com hora

110

05-29-2025

EUA com hífen

111

########

Japão

112

20250529

Compacto sem separadores

113

29 May 2025 15:45:12:123

Europa com hora

114

15:45:12:123

Hora completa

120

########

ISO sem milissegundos

121

2025-05-29 15:45:12.123

ISO com milissegundos

126

2025-05-29T15:45:12

ISO 8601 (T separador)

127

2025-05-29T15:45:12.123

ISO com milissegundos



Funções para extrair partes da data


SELECT 


    YEAR(data_pedido) AS Ano,

    MONTH(data_pedido) AS Mes,

    DAY(data_pedido) AS Dia,

    DATEPART(HOUR, data_pedido) AS Hora,

    DATEPART(MINUTE, data_pedido) AS Minuto

 

FROM pedidos



 Diferença entre datas


--- Diferença em dias

SELECT DATEDIFF(DAY, '2024-01-01', GETDATE()) AS DiasDesdeInicioDoAno;


-- Diferença em minutos

SELECT DATEDIFF(MINUTE, horario_entrada, horario_saida) AS TempoTrabalhado


-- Contagem de dias entre duas datas


       CASE

WHEN PFUNC.DATADEMISSAO IS NULL THEN DATEDIFF(DAY, PFUNC.DATAADMISSAO, GETDATE())

WHEN PFUNC.DATADEMISSAO IS NOT NULL THEN DATEDIFF(DAY, PFUNC.DATAADMISSAO, PFUNC.DATADEMISSAO)

       END AS 'QNT_DIAS'



 Adicionando/Subtraindo datas


-- Soma de 30 dias

SELECT DATEADD(DAY, 30, GETDATE()) AS DataFutura;


-- Subtrai 2 horas

SELECT DATEADD(HOUR, -2, GETDATE()) AS DuasHorasAtras;




Alterar dia para o último dia do mês


FORMAT(EOMONTH(PFUNC.DATADEMISSAO), 'dd/MM/yyyy') AS DATA_DEMISSAO,



Alterar data para o mês anterior


FORMAT(DATEADD(MONTH, -1, CONVERT(DATE, datCredito, 103)), 'dd/MM/yyyy') AS MES_ANT,


-- Data do mês anterior


format(DATEADD(MONTH, -1, GETDATE()), 'dd/MM/yyyy')


-- Data do mês anterior considerando o último dia do mês anterior


FORMAT(EOMONTH(DATEADD(MONTH, -1, GETDATE())), 'dd/MM/yyyy')


-- Buscar registros até o último dia do mês anterior


WHERE 

  ((AABONFUN.HORAFIM - AABONFUN.HORAINICIO) > 0)

  AND AABONFUN.DATA >= '2022-01-01'

  AND AABONFUN.DATA <= EOMONTH(GETDATE(), -1)


WHERE ((AABONFUN.HORAFIM-AABONFUN.HORAINICIO)>0) AND AABONFUN.DATA>='01/01/2022' AND  AABONFUN.DATA <= DATEADD(DAY, -1, EOMONTH(GETDATE(), -1))



-- Retornar as demissões do mês anterior + quadro de funcionários que estão ativos


 

AND (MONTH(PFUNC.DATADEMISSAO) >= (MONTH(GETDATE())-1)  AND YEAR(PFUNC.DATADEMISSAO) = (YEAR(GETDATE())))

 

OR (PFUNC.DATADEMISSAO IS NULL)


 Convertendo textos em datas


-- Convertendo string em data

SELECT CONVERT(DATE, '2024-05-29', 103); -- Formato BR (dd/mm/yyyy)

 

SELECT CAST('2024-05-29 14:00' AS DATETIME) AS DataHora;


-- Convertendo a data 20240506003506 06/05/2024 00:35:06

porem sem os segundos:


   -- Data e hora do saldo (formato AAAAMMDDHHMMSS → smalldatetime)


   CASE WHEN LEN([DtHoraSaldo]) = 14 THEN

        TRY_CAST(

            STUFF(STUFF(STUFF([DtHoraSaldo], 13, 0, ':'), 11, 0, ':'), 9, 0, ' ') AS smalldatetime

        ) ELSE NULL END AS [DtHoraSaldo],




Calculando a idade de uma pessoa


Um erro comum ao calcular a idade de uma pessoa é usar apenas o DATEDIFF(YEAR, data_nascimento, GETDATE()), pois ele considera apenas os anos completos entre as duas datas, sem se importar com o mês ou o dia.


▶ A forma mais precisa é comparar os anos e verificar se a data de aniversário já passou.

DATEDIFF(YEAR, nascimento, hoje) dá a diferença bruta em anos.

  1. DATEADD(...) soma esse número de anos à data de nascimento — ou seja, calcula o aniversário da pessoa neste ano.

  2. Se esse aniversário ainda não chegou, subtrai 1 da idade.



SELECT 

 

    FORMAT(DTNASCIMENTO, 'dd/MM/yyyy') AS DATA_NASCIMENTO,

    DATEDIFF(YEAR, DTNASCIMENTO, GETDATE()) 

 

CASE 

 WHEN DATEADD(YEAR, DATEDIFF(YEAR, DTNASCIMENTO, GETDATE()), DTNASCIMENTO) > GETDATE() 

  THEN 1

  ELSE 0

END AS IDADE_CORRETA

 

FROM PPESSOA;



▶ Também podemos calcular a idade com maior precisão usando uma combinação de FLOOR e o número de dias entre as datas. Essa abordagem é uma aproximação que considera anos bissextos (~365,25 dias), útil em relatórios rápidos, mas não tão precisa quanto a comparação direta de datas.


SELECT 

 

    FLOOR(DATEDIFF(DAY, DTNASCIMENTO, GETDATE()) / 365.25) AS IDADE_ESTIMADA

 

FROM PPESSOA;

Uma forma precisa e didática:


Ele calcula a idade com DATEDIFF(YEAR, nascimento, hoje) e depois verifica se a pessoa já fez aniversário neste ano:

  1. Se o mês de nascimento ainda não chegou → subtrai 1 da idade

  2. Se o mês é o mesmo, mas o dia ainda não chegou → subtrai 1 da idade

  3. Caso contrário, a idade está correta



CASE 

 

   WHEN MONTH(PFDEPEND.DTNASCIMENTO) > MONTH(GETDATE()) 

       THEN DATEDIFF(YEAR, PFDEPEND.DTNASCIMENTO, GETDATE()) - 1

  WHEN MONTH(PFDEPEND.DTNASCIMENTO) = MONTH(GETDATE()) AND      DAY(PFDEPEND.DTNASCIMENTO) > DAY(GETDATE()) 

THEN DATEDIFF(YEAR, PFDEPEND.DTNASCIMENTO, GETDATE()) - 1

 ELSE DATEDIFF(YEAR, PFDEPEND.DTNASCIMENTO, GETDATE()) 

  END AS Idade



Calculando o tempo de empresa através da data de demissão, admissão ou data atual



CONCAT(AVG(

 

  CASE

      WHEN PFUNC.DATADEMISSAO IS NULL THEN DATEDIFF(DAY, PFUNC.DATAADMISSAO, GETDATE())

      WHEN PFUNC.DATADEMISSAO IS NOT NULL THEN DATEDIFF(DAY, PFUNC.DATAADMISSAO, PFUNC.DATADEMISSAO)

    END

  ) / 365,' anos e ', 

 

  CASE

    WHEN FORMAT(CONCAT('0.',SUBSTRING((CAST(ROUND(AVG(

    CASE

        WHEN PFUNC.DATADEMISSAO IS NULL THEN DATEDIFF(DAY, PFUNC.DATAADMISSAO, GETDATE())

        WHEN PFUNC.DATADEMISSAO IS NOT NULL THEN DATEDIFF(DAY, PFUNC.DATAADMISSAO, PFUNC.DATADEMISSAO)

      END

    ) / 365.0, 2) AS varchar(38))), 3, 2)) * CAST(365 AS DECIMAL(18, 2)) / 30, '0') <= 1 THEN '1 mês'

    ELSE CONCAT(FORMAT(CONCAT('0.',SUBSTRING((CAST(ROUND(AVG(

  CASE

        WHEN PFUNC.DATADEMISSAO IS NULL THEN DATEDIFF(DAY, PFUNC.DATAADMISSAO, GETDATE())

        WHEN PFUNC.DATADEMISSAO IS NOT NULL THEN DATEDIFF(DAY, PFUNC.DATAADMISSAO, PFUNC.DATADEMISSAO)

      END

    ) / 365.0, 2) AS varchar(38))), 3, 2)) * CAST(365 AS DECIMAL(18, 2)) / 30, '0'), ' meses')

  END) AS ANOS_E_MESES




Relatórios que precisam de períodos mensais dinâmicos baseados na data atual



Se hoje for dia 15 ou depois: Pega o primeiro dia do mês atual

Se hoje for antes do dia 15: Pega o primeiro dia do mês anterior


SET @DataInicial = 

    CASE WHEN DAY(getdate())<15 THEN CONVERT(date, '01' + RIGHT(CONVERT(varchar(10), DATEADD(month, -1, getdate()), 105), 8), 105)

         ELSE CONVERT(date, '01' + RIGHT(CONVERT(varchar(10), getdate(), 105), 8), 105)

    END;

 

SET @DataFinal = CONVERT(date, getdate());


--Opção 2


SET @DataInicial = DATEADD(DAY, 1-DAY(getdate()), 

                  CASE WHEN DAY(getdate()) < 15 THEN DATEADD(MONTH, -1, getdate())

                       ELSE getdate() END);



O estilo 105 (dd-mm-yyyy) garante que a formatação seja consistente independente das configurações regionais do SQL Server.

Data Atual: 2024-02-10 (dia 10)

  1. CASE WHEN: 10 < 15? SIM → 2024-01-10

  2. DATEADD: 1-10 = -9 → 10/01 - 9 dias = 01/01 Resultado: 2024-01-01

Data Atual: 2024-02-20 (dia 20)

  1. CASE WHEN: 20 < 15? NÃO → 2024-02-20

  2. DATEADD: 1-20 = -19 → 20/02 - 19 dias = 01/02 Resultado: 2024-02-01

© 2017-2025  Criado e desenvolvido por Amanda Nascimento

  • Discord
  • GitHub
  • youtube
  • LinkedIn Amanda
bottom of page