PostgreSQL – How to Compare Time Portion of Multiple Dates

datepostgresql

I have a postgresql database with various records which have a date column which looks like 2020-10-12 12:45:55. I am wanting to construct a query that looks for activity with timestamps that are on any day, but between 22:00:00 of one day and 05:00:00 the next day in the actual time portion.

How do I ignore the date and just focus on the time portion of this column? I think I need to split up the date column, but still be able to use < and > operators on the time string which is left over.

Best Answer

which have a date column which looks like 2020-10-12 12:45:55

That's not a date column, but a timestamp (date and time). Assuming type timestamp, not timetamptz? (You should always disclose actual table definitions.)

SELECT *
FROM   tbl
WHERE  timestamp_in_disguise::time >= '22:00'
OR     timestamp_in_disguise::time <= '05:00';

See:

Or:

...
WHERE  timestamp_in_disguise::time NOT BETWEEN '05:00' AND '22:00';

The first includes bounds and you can adjust as needed.

The second uses BETWEEN, which always includes bounds - so excludes them in the negated expression.
You can still use a hack to include bounds building on the inside knowledge that Postgres stores times and timestamps with microsecond resolution (6 fractional decimal digits) in its current implementation.

...
WHERE  timestamp_in_disguise::time NOT BETWEEN '05:00:00.000001' AND '21:59:59.999999';

But I strongly advice against the latter. Building on implementation details is brittle and ugly.

Casting the string literals to the right is optional as their type is derived from the typed column.

If we are, in fact, dealing with timestamptz you need to define where in the world it's supposed to be 22:00 etc. (You may need to think about that with timestamp, too.) See:

About BETWEEN and including lower and upper bound:

If you run this kind of queries a lot, consider an expression index:

CREATE INDEX ON tbl ((timestamp_in_disguise::time));  -- parentheses needed