Quando voce soma e subtrai intervalos no PostgreSQL, o resultado costuma sair "bruto": 36 horas, 90 dias, 800 minutos. A familia JUSTIFY_* reorganiza esse intervalo em algo legivel, jogando as horas que sobram para dias e os dias que sobram para meses.
Tres funcoes e o que cada uma carrega
O PostgreSQL traz tres funcoes de normalizacao, cada uma responsavel por uma "casa":
JUSTIFY_HOURS(i) pega cada 24 horas e as transforma em 1 dia.
JUSTIFY_DAYS(i) pega cada 30 dias e os transforma em 1 mes.
JUSTIFY_INTERVAL(i) faz os dois transportes de uma vez e ajusta os sinais.
SELECT JUSTIFY_HOURS(INTERVAL '36 hours') AS h,
JUSTIFY_DAYS(INTERVAL '90 days') AS d,
JUSTIFY_INTERVAL(INTERVAL '1 mon 33 days 27 hours') AS full;
Repare que nenhuma delas achata o intervalo ate segundos. O PostgreSQL guarda um intervalo em tres campos independentes — meses, dias e microssegundos — e JUSTIFY_* apenas remaneja valores entre esses campos sem mudar o significado.
Para que serve: duracao de um pedido
Digamos que medimos ha quanto tempo um pedido esta em processamento. A subtracao simples de tempos da um intervalo onde tudo se acumula em horas:
SELECT id,
created_at,
NOW() - created_at AS raw_age
FROM orders
WHERE status = 'processing';
A string 52:30:00 esta tecnicamente correta, mas e desconfortavel num relatorio. Envolva o resultado em JUSTIFY_HOURS:
SELECT id,
JUSTIFY_HOURS(NOW() - created_at) AS readable_age
FROM orders
WHERE status = 'processing';
Agora se le como "2 dias e algumas horas" — exatamente o que um gestor espera ver.
Tempo de casa e grandes contagens de dias
JUSTIFY_DAYS e bem util quando voce acumula dias e quer uma estimativa aproximada em meses. Imagine agregar dias por departamento:
SELECT dept,
JUSTIFY_DAYS(SUM(NOW() - created_at)) AS dept_tenure
FROM employees
GROUP BY dept;
Quando um intervalo carrega horas e dias ao mesmo tempo, use JUSTIFY_INTERVAL — ele organiza em todas as frentes. Um bom habito e normalizar uma diferenca antes de compara-la, para que sinais misturados nao te peguem de surpresa:
SELECT name,
JUSTIFY_INTERVAL(salary_review_at - hired_at) AS service
FROM employees
ORDER BY service DESC;
Pegadinha: 30 dias nao e um mes de calendario
A armadilha principal de JUSTIFY_DAYS e JUSTIFY_INTERVAL e que elas tratam um mes como exatamente 30 dias. Meses reais nunca sao assim: fevereiro tem 28 ou 29 dias, julho tem 31.
SELECT JUSTIFY_INTERVAL(INTERVAL '60 days');
Por causa disso, um intervalo normalizado serve para relatorios e rotulos legiveis, mas e errado para aritmetica exata de datas. Tenha a distincao em mente:
JUSTIFY_* aplica regras fixas: 24 horas = 1 dia, 30 dias = 1 mes.
AGE(end, start) olha o calendario real e devolve meses e dias verdadeiros.
Se voce precisa de uma "idade" honesta, use AGE. Se so quer exibir uma duracao acumulada de forma organizada, use JUSTIFY_*.
Diferencas em outros bancos
As funcoes JUSTIFY_* sao especificas do PostgreSQL; nao ha equivalente direto em outros bancos.
- MySQL: nao existe um tipo
interval de primeira classe, entao as diferencas costumam viver como segundos ou dias. Voce normaliza na mao com DIV e MOD, por exemplo seconds DIV 86400 para dias.
- ClickHouse: os intervalos tambem nao se normalizam sozinhos; use
dateDiff('day', ...) e aritmetica numerica simples para derivar as casas que quiser.
Resumo: JUSTIFY_* e uma conveniencia de apresentacao que vive no PostgreSQL. Em codigo portavel, normalize as duracoes voce mesmo e lembre-se de que "um mes igual a 30 dias" e uma simplificacao, nao uma verdade do calendario.
Quando voce soma e subtrai intervalos no PostgreSQL, o resultado costuma sair "bruto": 36 horas, 90 dias, 800 minutos. A familia
JUSTIFY_*reorganiza esse intervalo em algo legivel, jogando as horas que sobram para dias e os dias que sobram para meses.Tres funcoes e o que cada uma carrega
O PostgreSQL traz tres funcoes de normalizacao, cada uma responsavel por uma "casa":
JUSTIFY_HOURS(i)pega cada 24 horas e as transforma em 1 dia.JUSTIFY_DAYS(i)pega cada 30 dias e os transforma em 1 mes.JUSTIFY_INTERVAL(i)faz os dois transportes de uma vez e ajusta os sinais.SELECT JUSTIFY_HOURS(INTERVAL '36 hours') AS h, -- 1 day 12:00:00 JUSTIFY_DAYS(INTERVAL '90 days') AS d, -- 3 mons JUSTIFY_INTERVAL(INTERVAL '1 mon 33 days 27 hours') AS full; -- full -> 2 mons 4 days 03:00:00Repare que nenhuma delas achata o intervalo ate segundos. O PostgreSQL guarda um intervalo em tres campos independentes — meses, dias e microssegundos — e
JUSTIFY_*apenas remaneja valores entre esses campos sem mudar o significado.Para que serve: duracao de um pedido
Digamos que medimos ha quanto tempo um pedido esta em processamento. A subtracao simples de tempos da um intervalo onde tudo se acumula em horas:
SELECT id, created_at, NOW() - created_at AS raw_age FROM orders WHERE status = 'processing'; -- raw_age poderia ser, por exemplo, '52:30:00'A string
52:30:00esta tecnicamente correta, mas e desconfortavel num relatorio. Envolva o resultado emJUSTIFY_HOURS:SELECT id, JUSTIFY_HOURS(NOW() - created_at) AS readable_age FROM orders WHERE status = 'processing'; -- readable_age -> 2 days 04:30:00Agora se le como "2 dias e algumas horas" — exatamente o que um gestor espera ver.
Tempo de casa e grandes contagens de dias
JUSTIFY_DAYSe bem util quando voce acumula dias e quer uma estimativa aproximada em meses. Imagine agregar dias por departamento:SELECT dept, JUSTIFY_DAYS(SUM(NOW() - created_at)) AS dept_tenure FROM employees GROUP BY dept;Quando um intervalo carrega horas e dias ao mesmo tempo, use
JUSTIFY_INTERVAL— ele organiza em todas as frentes. Um bom habito e normalizar uma diferenca antes de compara-la, para que sinais misturados nao te peguem de surpresa:SELECT name, JUSTIFY_INTERVAL(salary_review_at - hired_at) AS service FROM employees ORDER BY service DESC;Pegadinha: 30 dias nao e um mes de calendario
A armadilha principal de
JUSTIFY_DAYSeJUSTIFY_INTERVALe que elas tratam um mes como exatamente 30 dias. Meses reais nunca sao assim: fevereiro tem 28 ou 29 dias, julho tem 31.SELECT JUSTIFY_INTERVAL(INTERVAL '60 days'); -- 2 mons (nao "1 mes mais alguns dias de calendario")Por causa disso, um intervalo normalizado serve para relatorios e rotulos legiveis, mas e errado para aritmetica exata de datas. Tenha a distincao em mente:
JUSTIFY_*aplica regras fixas: 24 horas = 1 dia, 30 dias = 1 mes.AGE(end, start)olha o calendario real e devolve meses e dias verdadeiros.Se voce precisa de uma "idade" honesta, use
AGE. Se so quer exibir uma duracao acumulada de forma organizada, useJUSTIFY_*.Diferencas em outros bancos
As funcoes
JUSTIFY_*sao especificas do PostgreSQL; nao ha equivalente direto em outros bancos.intervalde primeira classe, entao as diferencas costumam viver como segundos ou dias. Voce normaliza na mao comDIVeMOD, por exemploseconds DIV 86400para dias.dateDiff('day', ...)e aritmetica numerica simples para derivar as casas que quiser.Resumo:
JUSTIFY_*e uma conveniencia de apresentacao que vive no PostgreSQL. Em codigo portavel, normalize as duracoes voce mesmo e lembre-se de que "um mes igual a 30 dias" e uma simplificacao, nao uma verdade do calendario.