SQL Datas e Horas

Quase todo banco de dados guarda datas: o dia do pedido, o dia da entrega, o aniversário do cliente, a hora do pagamento. A Loja Aurora tem 90 pedidos, de janeiro de 2024 a outubro de 2026, e a Ana precisa responder perguntas como "quantos pedidos tivemos em 2025?" e "o que foi pago no dia 14?". Nesta aula você vai entender como o SQLite guarda datas e horas (ele não tem um tipo de data próprio!), por que o formato AAAA-MM-DD é o único que funciona bem, como filtrar por período sem cair na armadilha do BETWEEN, e como pegar a data de hoje.

Você vai aprender
  • Que o SQLite não tem tipo DATE: as datas são texto (ou número), e o formato ISO 8601 (2025-03-14) é o combinado.
  • Por que AAAA-MM-DD ordena e compara certo, e DD/MM/AAAA não.
  • Filtrar por ano, por mês e por período com >=, <, BETWEEN e LIKE.
  • Data com hora (2026-10-14 16:45:10) e a armadilha do BETWEEN com elas.
  • Os três jeitos de guardar o mesmo instante: texto, dia juliano e tempo Unix.
  • A data e a hora de agora: date('now'), CURRENT_DATE, CURRENT_TIMESTAMP, e por que elas vêm em UTC.
  • Como impedir que uma data impossível (2024-02-30, 30/01/2024) entre na tabela.

Os exemplos rodam de verdade no seu navegador, num SQLite com o banco da Loja Aurora, e cada exemplo parte do banco limpo. As sessões de terminal saíram do sqlite3 3.50.4 no computador fictício da Ana. As funções de data (date, strftime, somar dias, descobrir o dia da semana…) têm aula própria, logo depois desta: Funções de Data.


A ideia: escrever a data de um jeito que ordena

Pense numa pasta de fotos no computador. Se cada arquivo se chama 05-01-2024.jpg, 14-01-2024.jpg, 27-12-2023.jpg, o computador põe em ordem pelo dia (05, 14, 27), misturando meses e anos. Quem já sofreu com isso passou a nomear as fotos assim: 2023-12-27.jpg, 2024-01-05.jpg, 2024-01-14.jpg. Com o ano primeiro, depois o mês, depois o dia, sempre com dois dígitos, a ordem alfabética dos nomes é a mesma ordem do calendário.

O SQLite usa exatamente esse truque. Ele não tem um tipo especial para datas (veja Os Tipos no SQLite): uma data é um texto comum, como '2025-03-14'. Esse formato, ano-mês-dia com hífens, é um padrão internacional, o ISO 8601. Todas as funções de data do SQLite entendem esse formato, e, como o ano vem primeiro, ordenar e comparar o texto dá o mesmo que ordenar e comparar as datas.

ParteFormatoExemplo
DataAAAA-MM-DD (ano com 4 dígitos, mês e dia com 2)2025-03-14
HoraHH:MM:SS (0 a 23 horas)16:45:10
Data e horaAAAA-MM-DD HH:MM:SS (um espaço no meio; um T também vale)2026-10-14 16:45:10

1. As datas da Loja Aurora

A tabela pedidos tem duas colunas de data: data (o dia do pedido) e entregue_em (o dia da entrega, ou NULL se ainda não chegou). A função typeof ("tipo de") mostra como cada valor está guardado:

SELECT id, data, entregue_em,
       typeof(data) AS tipo_data,
       typeof(entregue_em) AS tipo_entrega
FROM pedidos
WHERE id IN (1, 2, 86);
data
O dia do pedido, como texto ISO: 2024-01-05 é 5 de janeiro de 2024.
entregue_em
O dia da entrega. O pedido 86 ainda não foi entregue: NULL (veja O Valor NULL).
typeof(data)
text: a data é um texto. Não existe "tipo data" no SQLite.
typeof(entregue_em)
null no pedido 86: é a ausência de valor, não uma data.

Na tabela clientes, a coluna nascimento usa o mesmo formato. Dois clientes (9 e 21) estão sem data de nascimento.


2. Ordenar e comparar: por que ano-mês-dia

Com as datas em ISO, o ORDER BY (aula ORDER BY) põe os clientes do mais velho para o mais novo sem nenhum esforço:

SELECT nome, nascimento
FROM clientes
WHERE nascimento IS NOT NULL
ORDER BY nascimento
LIMIT 5;

Agora veja o que acontece quando alguém guarda as datas do jeito brasileiro, DD/MM/AAAA. A Ana fez uma tabelinha de aniversários da equipe:

CREATE TABLE aniversarios (nome TEXT, dia TEXT);
INSERT INTO aniversarios VALUES
  ('Ana',    '05/01/2024'),
  ('Caio',   '14/01/2024'),
  ('Renata', '27/12/2023'),
  ('Pedro',  '03/02/2024');

SELECT * FROM aniversarios ORDER BY dia;

A ordem saiu errada: Pedro (fevereiro de 2024) veio primeiro e Renata (dezembro de 2023) ficou por último. O SQLite não sabe que aquilo é uma data; ele ordenou o texto, letra por letra, e comparou primeiro os dias: 03, 05, 14, 27. Com comparações, o estrago é o mesmo: WHERE dia > '01/01/2024' traria a Renata, de 2023.

Guarde em ISO, mostre como quiser

Grave sempre AAAA-MM-DD no banco. Na hora de mostrar para o cliente, aí sim converta para 14/03/2025, com strftime('%d/%m/%Y', data) (aula Funções de Data). Banco é para guardar certo; a tela é para mostrar bonito.


3. Filtrar por período

Como data ISO compara certo, filtrar por período é usar os operadores que você já conhece (aula Comparações) com texto entre aspas simples.

Um ano inteiro

SELECT COUNT(*) AS pedidos_2025
FROM pedidos
WHERE data >= '2025-01-01' AND data < '2026-01-01';
data >= '2025-01-01'
Do primeiro dia de 2025 em diante (incluindo ele).
AND
As duas condições ao mesmo tempo (aula AND).
data < '2026-01-01'
Antes do primeiro dia de 2026 (sem incluí-lo).

Foram 32 pedidos em 2025. Esse jeito, "maior ou igual ao início e menor que o início do período seguinte", é o mais seguro de todos: funciona igual para datas com e sem hora, e você nunca precisa saber se o mês acaba no dia 28, 30 ou 31.

Com BETWEEN

O BETWEEN ("entre", aula BETWEEN) inclui as duas pontas. Para datas sem hora, como as da loja, ele funciona bem:

SELECT COUNT(*) AS pedidos_2025
FROM pedidos
WHERE data BETWEEN '2025-01-01' AND '2025-12-31';

Os mesmos 32. Mas guarde a palavra "sem hora": na seção 4 você vai ver o BETWEEN errar.

Um mês com LIKE

Como a data é texto, dá para usar o LIKE (aula LIKE): todo dia de março de 2025 começa com 2025-03-.

SELECT id, data
FROM pedidos
WHERE data LIKE '2025-03-%';

Funciona, e é fácil de ler. A desvantagem é que o LIKE trata a data só como texto; com >= e < o banco consegue usar um índice na coluna de data (aula Índices), e o LIKE, em geral, não.

Experimente: a Ana quer os pedidos de dezembro de 2025. A consulta tem só o começo do período, e trouxe dezembro de 2025 e tudo o que veio depois. Acrescente o fim do período.

SELECT id, data
FROM pedidos
WHERE data >= '2025-12-01';
SELECT id, data
FROM pedidos
WHERE data >= '2025-12-01' AND data < '2026-01-01';

4. Data com hora e a armadilha do BETWEEN

Quando a hora importa, ela vem depois da data, separada por um espaço: '2026-10-14 16:45:10'. A Ana anotou os pagamentos dos últimos pedidos numa tabela nova, com a hora exata de cada um:

CREATE TABLE pagamentos (pedido_id INTEGER, pago_em TEXT);
INSERT INTO pagamentos VALUES
  (88, '2026-10-05 09:12:40'),
  (89, '2026-10-09 18:03:05'),
  (90, '2026-10-14 08:30:00'),
  (87, '2026-10-14 16:45:10'),
  (86, '2026-10-15 00:00:00');

SELECT * FROM pagamentos ORDER BY pago_em;

Ordenou certo, de novo: o formato ISO com hora também ordena como texto. Agora a pergunta: "o que foi pago no dia 14?". A primeira ideia de muita gente:

CREATE TABLE pagamentos (pedido_id INTEGER, pago_em TEXT);
INSERT INTO pagamentos VALUES
  (88, '2026-10-05 09:12:40'), (89, '2026-10-09 18:03:05'),
  (90, '2026-10-14 08:30:00'), (87, '2026-10-14 16:45:10'),
  (86, '2026-10-15 00:00:00');

SELECT * FROM pagamentos
WHERE pago_em BETWEEN '2026-10-14' AND '2026-10-14';

Zero linhas, e houve dois pagamentos no dia 14! Por quê? Para o SQLite, '2026-10-14' é só um texto, e quer dizer "dia 14 à meia-noite em ponto". O texto '2026-10-14 08:30:00' é maior que '2026-10-14' (é mais comprido e começa igual), então está fora do intervalo. A tentativa seguinte também erra:

FiltroO que vemCerto?
BETWEEN '2026-10-14' AND '2026-10-14'NadaNão
BETWEEN '2026-10-14' AND '2026-10-15'Os dois do dia 14Por sorte. O pagamento '2026-10-15 00:00:00' ficou de fora porque é maior que '2026-10-15'; mas um pagamento gravado só como '2026-10-15' entraria, e ele é do dia 15
pago_em >= '2026-10-14' AND pago_em < '2026-10-15'Só os dois do dia 14Sim
date(pago_em) = '2026-10-14'Só os dois do dia 14Sim (mas não usa índice)
pago_em LIKE '2026-10-14%'Só os dois do dia 14Sim

A date(pago_em) corta a hora e deixa só a data; ela é da próxima aula (Funções de Data). A regra que resolve tudo é a mesma da seção 3: maior ou igual ao começo, menor que o começo do dia seguinte.

Missão: conserte o filtro para trazer os dois pagamentos do dia 14 de outubro de 2026, e só eles.

CREATE TABLE pagamentos (pedido_id INTEGER, pago_em TEXT);
INSERT INTO pagamentos VALUES
  (88, '2026-10-05 09:12:40'), (89, '2026-10-09 18:03:05'),
  (90, '2026-10-14 08:30:00'), (87, '2026-10-14 16:45:10'),
  (86, '2026-10-15 00:00:00');

SELECT * FROM pagamentos
WHERE pago_em BETWEEN '2026-10-14' AND '2026-10-14';
CREATE TABLE pagamentos (pedido_id INTEGER, pago_em TEXT);
INSERT INTO pagamentos VALUES
  (88, '2026-10-05 09:12:40'), (89, '2026-10-09 18:03:05'),
  (90, '2026-10-14 08:30:00'), (87, '2026-10-14 16:45:10'),
  (86, '2026-10-15 00:00:00');

SELECT * FROM pagamentos
WHERE pago_em >= '2026-10-14' AND pago_em < '2026-10-15';

5. Três jeitos de guardar o mesmo instante

O texto ISO é o jeito mais comum, mas o SQLite aceita mais dois. Os três representam o mesmo dia, o do primeiro pedido da loja:

SELECT '2024-01-05'              AS texto_iso,
       julianday('2024-01-05')   AS dia_juliano,
       unixepoch('2024-01-05')   AS tempo_unix;
FormatoTipoO que éBom para
Texto ISO 8601TEXT'2024-01-05' ou '2024-01-05 08:30:00'Quase tudo: dá para ler a olho, ordena certo. É o recomendado e o que a Loja Aurora usa.
Dia julianoREALQuantos dias se passaram desde o meio-dia de 24 de novembro de 4714 a.C. (um marco dos astrônomos). A parte depois do ponto é a fração do dia: o .5 quer dizer meia-noite.Fazer contas: a diferença entre dois dias julianos é o número de dias entre as datas.
Tempo UnixINTEGERQuantos segundos se passaram desde 1º de janeiro de 1970, à meia-noite em UTC.Trocar dados com programas: quase toda linguagem (PHP, Python, JavaScript) fala esse número.

As funções de data convertem de um para o outro. A date() volta para o texto ISO; com tempo Unix, é preciso avisar com 'unixepoch', senão ela acharia que o número é um dia juliano:

SELECT date(2460314.5)                    AS do_juliano,
       date(1704412800, 'unixepoch')      AS do_unix,
       datetime(1704412800, 'unixepoch')  AS do_unix_com_hora;

Uma conta com dias julianos

Quantos dias cada pedido levou para ser entregue? Subtraindo os dias julianos das duas datas:

SELECT id, data, entregue_em,
       julianday(entregue_em) - julianday(data) AS dias
FROM pedidos
WHERE id <= 3;

O pedido 1 levou 5 dias, de 5 a 10 de janeiro. Subtrair os textos direto (entregue_em - data) não funciona: o SQLite transforma cada texto em número aproveitando só o 2024 do começo, e a conta dá 0. Essa e as outras contas de data estão em Funções de Data.


6. A data e a hora de agora

Para saber o dia de hoje, o SQLite tem a função date('now') ("agora") e três palavras do SQL padrão: CURRENT_DATE ("data atual"), CURRENT_TIME ("hora atual") e CURRENT_TIMESTAMP ("data e hora atuais"). Elas dão uma resposta diferente a cada dia (e a cada segundo), então a sessão abaixo mostra o que a Ana viu numa manhã de outubro de 2026:

$ sqlite3 loja.db
SQLite version 3.50.4 2025-07-30 19:33:53
Enter ".help" for usage hints.
sqlite> SELECT date('now');
2026-10-18
sqlite> SELECT CURRENT_DATE, CURRENT_TIME;
2026-10-18|13:40:15
sqlite> SELECT CURRENT_TIMESTAMP;
2026-10-18 13:40:15                « 13h40 em UTC
sqlite> SELECT datetime('now', 'localtime');
2026-10-18 10:40:15                « 10h40 no relógio da Ana (horário de Brasília)
sqlite> .quit

Repare na diferença de 3 horas. O SQLite dá a hora de agora em UTC (o "tempo universal coordenado", a hora de Greenwich, a referência do mundo inteiro), e não na hora local. No horário de Brasília, o relógio está 3 horas atrás do UTC. Para a hora do relógio da parede, acrescente 'localtime' ("hora local"). Guardar em UTC é, na verdade, uma boa prática: um sistema com clientes em Fortaleza, Lisboa e Buenos Aires tem uma hora só como referência.

Por que o guia evita now nos exemplos

Uma consulta com date('now') dá uma resposta hoje e outra amanhã. Se esta aula dissesse "a consulta abaixo devolve 3 pedidos", a frase ficaria errada na semana que vem. Por isso os exemplos usam datas fixas dos pedidos da loja (como '2026-10-14', a data do último pedido). No editor do guia você pode rodar SELECT date('now'); à vontade: vai ver a data do seu computador, em UTC.

Gravar a hora automaticamente

O uso mais comum do CURRENT_TIMESTAMP é como valor padrão (DEFAULT, aula DEFAULT) de uma coluna "criado em": cada linha nova anota sozinha quando foi gravada.

$ sqlite3 loja.db
SQLite version 3.50.4 2025-07-30 19:33:53
Enter ".help" for usage hints.
sqlite> CREATE TABLE avisos (id INTEGER PRIMARY KEY, texto TEXT, criado_em TEXT DEFAULT CURRENT_TIMESTAMP);
sqlite> INSERT INTO avisos (texto) VALUES ('Chegou o estoque de cadernos');
sqlite> SELECT * FROM avisos;
1|Chegou o estoque de cadernos|2026-10-18 13:40:15
sqlite> DROP TABLE avisos;
sqlite> .quit

O INSERT não disse nada sobre criado_em, e a coluna recebeu a data e a hora do momento, em UTC. No editor, onde o resultado mudaria a cada segundo, dá para conferir só o formato:

CREATE TABLE avisos (
  id        INTEGER PRIMARY KEY,
  texto     TEXT,
  criado_em TEXT DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO avisos (texto) VALUES ('Chegou o estoque de cadernos');

SELECT texto, typeof(criado_em) AS tipo, length(criado_em) AS tamanho
FROM avisos;

Um texto de 19 caracteres: AAAA-MM-DD HH:MM:SS.


7. O SQLite aceita qualquer coisa: proteja a coluna

Como a data é só texto, o SQLite grava o que você mandar, sem reclamar. Até numa coluna declarada como DATE:

CREATE TABLE eventos (dia DATE);
INSERT INTO eventos VALUES ('2024-02-30'), ('ontem'), (20240105);

SELECT dia, typeof(dia) AS tipo FROM eventos;

Um 30 de fevereiro, a palavra "ontem" e um número: tudo entrou. O nome DATE no CREATE TABLE não faz o SQLite conferir nada (ele só influencia a "afinidade" da coluna, assunto de Os Tipos no SQLite). Quem confere é a função date(): ela devolve a data no formato ISO, ou NULL quando não entende o texto.

SELECT date('2024-02-29') AS bissexto,
       date('2024-02-30') AS dia_30,
       date('30/01/2024') AS formato_br,
       date('2024-1-5')   AS sem_zeros;

Três surpresas: '30/01/2024' e '2024-1-5' (sem os zeros) não são entendidos e viram NULL; e o '2024-02-30' não vira NULL, vira 2024-03-01: o SQLite "empurra" o dia que sobrou para o mês seguinte. O truque para validar é comparar o valor com a date() dele: só uma data correta e bem escrita continua igual. Use isso num CHECK (aula CHECK):

CREATE TABLE eventos (
  dia TEXT CHECK (dia IS date(dia))
);
INSERT INTO eventos VALUES ('2024-02-29');   -- passa
INSERT INTO eventos VALUES ('2024-02-30');   -- é recusado
CHECK (…)
Uma regra que toda linha precisa cumprir.
dia IS date(dia)
O texto guardado tem de ser igual à data que a date() entende. '2024-02-30' vira '2024-03-01': diferente, recusado. '30/01/2024' vira NULL: diferente, recusado.
IS
Por que IS e não =? Com =, '30/01/2024' = NULL dá NULL, e um CHECK que dá NULL deixa passar. O IS compara de verdade, até com NULL (aula IS NULL). Bônus: uma linha sem data (NULL) passa, porque NULL IS NULL é verdadeiro; para proibir, junte NOT NULL.

O primeiro INSERT passou; o segundo parou com CHECK constraint failed: dia IS date(dia), "a restrição CHECK falhou".


8. Formas diferentes de filtrar um período

Todas estas trazem os pedidos de março de 2025 (os pedidos 38, 39 e 40):

FormaExemploPrós e contras
>= início AND < início do seguintedata >= '2025-03-01' AND data < '2025-04-01'A recomendada. Certa com ou sem hora, usa índice, não precisa saber o último dia do mês.
BETWEENdata BETWEEN '2025-03-01' AND '2025-03-31'Fácil de ler. Certa só se a coluna não tiver hora.
LIKEdata LIKE '2025-03-%'Curta. Trata a data como texto; em geral, sem índice.
Função de datastrftime('%Y-%m', data) = '2025-03'Muito flexível (dia da semana, trimestre…), mas calcula linha por linha, sem índice. Veja Funções de Data.

Quando dá errado

Erros de data quase nunca dão mensagem de erro: a consulta roda e traz o resultado errado, ou nenhum. Por isso é preciso conhecer os casos.

A data escrita sem os zeros
SELECT COUNT(*) AS pedidos
FROM pedidos
WHERE data = '2024-1-5';

O que aconteceu: zero pedidos, e existe um pedido em 5 de janeiro de 2024 (o pedido 1). A coluna guarda '2024-01-05', e o texto '2024-1-5' é outro texto. Nenhum aviso.

Como consertar: sempre com zeros: '2024-01-05'.

A data no formato brasileiro
SELECT COUNT(*) AS pedidos
FROM pedidos
WHERE data = '05/01/2024';

O que aconteceu: zero, de novo. E com > ou < é pior: o resultado vem, mas errado, porque o texto '05/01/2024' é comparado letra por letra com '2024-…'.

Como consertar: no SQL, escreva sempre a data como 'AAAA-MM-DD'.

Esqueceu as aspas
SELECT COUNT(*) AS pedidos
FROM pedidos
WHERE data = 2024-01-05;

O que aconteceu: sem aspas, 2024-01-05 é uma conta: 2024 menos 1 menos 5, que dá 2018. A consulta procurou pedidos com data igual ao número 2018 e não achou nenhum. Sem erro, sem aviso.

Como consertar: data é texto, e texto vai entre aspas simples: '2024-01-05'.

Aspas duplas em vez de simples
SELECT COUNT(*) AS pedidos
FROM pedidos
WHERE data = "2024-01-05";

O que aconteceu: no such column: "2024-01-05" - should this be a string literal in single-quotes?: "não existe a coluna "2024-01-05"; isto deveria ser um texto entre aspas simples?". No SQL, aspas duplas são para nomes de colunas e tabelas; texto, inclusive datas, vai entre aspas simples.

Como consertar: WHERE data = '2024-01-05'.

BETWEEN numa coluna com hora

Você já viu na seção 4: pago_em BETWEEN '2026-10-14' AND '2026-10-14' não traz nada, porque '2026-10-14 08:30:00' é maior que '2026-10-14'. Como consertar: pago_em >= '2026-10-14' AND pago_em < '2026-10-15'.

Achou que a hora de agora era a do relógio

CURRENT_TIMESTAMP e datetime('now') vêm em UTC, 3 horas à frente do horário de Brasília. Um relatório "pedidos de hoje" rodado às 22h em Teresina já estaria no dia seguinte em UTC. Como consertar: guarde em UTC e, para mostrar ou comparar com a hora local, use datetime('now', 'localtime') (seção 6).

Nos outros bancos

MySQL, PostgreSQL e SQL Server têm tipos de data de verdade, e conferem o valor na hora de gravar. A data é escrita do mesmo jeito, como texto ISO entre aspas simples ('2025-03-14'), mas o banco a transforma num valor de data.

BancoTiposAgora
SQLiteNenhum: TEXT (ISO), REAL ou INTEGERCURRENT_TIMESTAMP, datetime('now') (UTC)
PostgreSQLDATE, TIME, TIMESTAMP, TIMESTAMP WITH TIME ZONE, INTERVALCURRENT_DATE, CURRENT_TIMESTAMP, now()
MySQLDATE, TIME, DATETIME, TIMESTAMP, YEARCURRENT_DATE, CURRENT_TIMESTAMP, NOW()
SQL Serverdate, time, datetime, datetime2, datetimeoffsetCURRENT_TIMESTAMP, GETDATE(), SYSDATETIME()

Numa coluna DATE do PostgreSQL ou do SQL Server, um '2024-02-30' é recusado com erro. O MySQL também recusa no modo estrito (o modo que vem ligado de fábrica); se o modo estrito estiver desligado, ele grava a "data zero" 0000-00-00 com um aviso. No SQLite, a proteção é o CHECK da seção 7. Trecho ilustrativo, que não roda no SQLite:

-- PostgreSQL: a coluna é do tipo DATE de verdade
CREATE TABLE pedidos (id INTEGER PRIMARY KEY, data DATE NOT NULL);
SELECT data + 7 FROM pedidos;   -- soma 7 dias direto na data

Referência rápida

EscritaO que é / o que faz
'2025-03-14'Uma data (texto ISO 8601: ano-mês-dia, com zeros)
'2025-03-14 16:45:10'Data e hora (24 horas)
col >= '2025-03-01' AND col < '2025-04-01'Um período (março de 2025), certo com ou sem hora
col BETWEEN '2025-03-01' AND '2025-03-31'Um período, só para colunas sem hora
col LIKE '2025-03-%'Um mês, comparando o texto
julianday(data)A data como dia juliano (REAL); diferença = dias
unixepoch(data)A data como tempo Unix (segundos desde 1970)
date(numero) / date(numero, 'unixepoch')Volta de juliano / de Unix para texto ISO
date('now'), CURRENT_DATEA data de hoje (UTC)
CURRENT_TIMEA hora de agora (UTC)
CURRENT_TIMESTAMP, datetime('now')Data e hora de agora (UTC)
datetime('now', 'localtime')Data e hora de agora no fuso do computador
DEFAULT CURRENT_TIMESTAMPColuna que anota sozinha quando a linha foi gravada
CHECK (col IS date(col))Só aceita datas válidas no formato AAAA-MM-DD

Exercícios

1. Escreva a data

Escreva o dia 7 de março de 2025 no formato que o SQLite entende (com as aspas):

WHERE data =

2. Complete o período

Pedidos do ano de 2024 inteiro, do jeito recomendado:

WHERE data >= '2024-01-01' AND data '2025-01-01'

3. Por que o SQLite consegue ordenar as datas da Loja Aurora com um simples ORDER BY data?

4. A coluna pago_em guarda data e hora. Quantas linhas WHERE pago_em BETWEEN '2026-10-14' AND '2026-10-14' traz para os pagamentos feitos às 08:30 e às 16:45 do dia 14?

5. A Ana rodou SELECT CURRENT_TIMESTAMP; às 10h da manhã em Teresina. Que hora apareceu?

6. O que date('2024-02-30') devolve no SQLite?

Missão final: os clientes dos anos 90

Missão: a loja vai fazer uma campanha para os clientes nascidos nos anos 90 (de 1º de janeiro de 1990 a 31 de dezembro de 1999). Mostre o nome e o nascimento deles, do mais velho para o mais novo.

SELECT nome, nascimento
FROM clientes;
SELECT nome, nascimento
FROM clientes
WHERE nascimento >= '1990-01-01' AND nascimento < '2000-01-01'
ORDER BY nascimento;

São 12 clientes, do Rafael Monteiro (maio de 1990) à Larissa Macêdo (janeiro de 1999). Os dois clientes sem data de nascimento ficaram de fora sozinhos: NULL >= '1990-01-01' não é verdadeiro.


Resumo

  • O SQLite não tem tipo de data. O combinado é guardar texto no formato ISO 8601: 'AAAA-MM-DD' ou 'AAAA-MM-DD HH:MM:SS', sempre com zeros.
  • Com o ano primeiro, a ordem do texto é a ordem do calendário: ORDER BY, < e > funcionam. DD/MM/AAAA ordena e compara errado.
  • Para um período, use col >= início AND col < início do próximo. O BETWEEN só é seguro em colunas sem hora.
  • O mesmo instante pode ser texto ISO, dia juliano (julianday, bom para contas) ou tempo Unix (unixepoch, segundos desde 1970).
  • date('now'), CURRENT_DATE e CURRENT_TIMESTAMP dão o momento atual em UTC; 'localtime' dá a hora do relógio. Mudam a cada dia: nunca dependa delas para um resultado fixo.
  • O SQLite grava qualquer texto como data. Proteja a coluna com CHECK (col IS date(col)).