Eu tenho uma tabela que representa intervalos de tempo.
Column | Type | Modifiers
-------------+-----------------------------+--------------------------------------------------------------------------
id | bigint | not null default nextval('exploded_recurring_sessions_id_seq'::regclass)
schedule_id | bigint |
start_time | time without time zone |
end_time | time without time zone |
Vou então fazer uma consulta como esta:
select from my_table where localtime >= start_time and localtime < end_time;
A lógica de negócios aqui faz sentido no caso em que end_time é meia-noite, porque considero que um intervalo inclui start_time e não inclui end_time.
É claro que essa consulta não funciona, porque localtime nunca será < end_time quando end_time for 00:00:00.
Existem duas soluções para isso que eu posso pensar.
- em vez de
00:00:00
, use'00:00:00'::time without time zone - interval '1 microsecond'
para meia-noite. A probabilidade de isso causar um cálculo incorreto provavelmente é baixa o suficiente para nunca acontecer. E mesmo que isso aconteça algumas vezes por ano, as consequências são essencialmente inexistentes, pelo menos como meu sistema está agora. No entanto, é uma solução feia, e usar dados errados como esse pode ter outras consequências no futuro. select from my_table where localtime >= start_time and (localtime < end_time or end_time == '00:00:00')
. Isso parece bastante simples, mas torna necessário fazer um ou mais índices especiais. Não é um problema se for a única solução, mas parece uma desvantagem que vale a pena evitar, se possível.
Existe alguma outra maneira de fazer isso? Algum tipo de função especial de data e hora que acomoda esse cálculo? Uma maneira melhor de representar os dados?
Introdução
Você pode querer considerar que
23:59:59.999
pertence ao dia atual.00:00:00.000
é considerada a transição de um dia para o outro. Deixe-me explicar...Referência: Midnight (Wikepedia).
Notação de 24 horas
Dependendo se você estiver usando a notação de 24 horas ou a notação de 12 horas am/pm, as informações a seguir podem ser igualmente interessantes.
Meio dia / Almoço
O meio-dia não é um problema com a notação de 24 horas porque o passo de
11:59:59.999
para12:00:00.000
e adiante12:00:00.001
não tem impacto no formato da hora.Meia-noite
Olhando para as horas por volta da meia-noite, você descobrirá que
23:59:59.999
ainda é o mesmo dia, enquanto00:00:00.001
pertence ao dia seguinte. Seguindo esta lógica o valor estático00:00:00.000
não deve pertencer a nenhum dia. É o ponto de transição.No entanto, alguns sistemas RDBMS mudarão a data ao adicionar
0.001 s
a arquivos2018-03-07 23:59:59.999
.notação de 12 horas
Meio dia / Almoço
Meio-dia na notação de 12 horas não é nem am nem pm , embora os relógios tendam a adicionar um PM assim que o relógio salta de
11:59:59.999
para12:00:00.000
. Na verdade, o meio-dia deve ter um únicom
adicionado quando estático, visto quea.m.
é definido como ante-meridiem que se traduz em antes do meio-dia ep.m.
que pós-merdiem se traduz em depois do meio-dia .Meia-noite
Isso é igualmente válido para a notação de 12 horas por volta da meia-noite.
11:59:59.999 p.m
é perto da meia-noite.12:00:00.001 a.m.
é logo depois da meia-noite.12:00:00 a.m./p.m.
é meia-noite e é exatamente 12 horas após o meio-dia ou antes do novo meio-dia.No entanto, a maioria dos sistemas decide adicionar um
a.m.
assim que o relógio atingir a meia-noite às 12 horas.Exemplos
PostgreSQL
Adicionando um milissegundo a um
timestamp
valor.Entrada:
Resultado:
servidor SQL
Adicionando um milissegundo a um
datetime
valor.Entrada:
Resultado:
Recomendações
Como você pode ver com os exemplos, ambos os sistemas RDBMS testados determinam
00:00:00.000
ser a hora (depois ou rotatória) meia-noite, mas para o dia seguinte.Se você não estiver usando datas junto com a hora, evite usar
00:00:00.000
como notação para a meia-noite seguinte23:59:59.999
(ou11:59:59.999 p.m.
) do mesmo dia. Isso corresponde à sua solução número 1.Se você estiver usando datas junto com as horas, descubra qual notação seu RDBMS suporta ao adicionar um microssegundo a um
2018-03-07 11:59:59.999
ou2018-03-07 11:59:59.999 p.m.
Lista de Referência Completa
Resposta do wiki da comunidade :
O que há de errado com
'24:00:00'::time
?24:00:00
é convertido para00:00:00
o dia seguinte (no PostgreSQL), então2018-03-07 24:00:00
é o mesmo que2018-03-08 00:00:00
.