Many ways.
We are talking about the type timestamp
. The preferred type in Postgres is timestamptz
. Be aware of the difference! See:
Using the column name ts
in my examples. "date" for a timestamp column would be misleading.
Last second of the same day
1.
ts::date + 1 - interval '1 sec'
Cast to date
, add integer '1'
, then subtracting interval '1 second'
.
The addition date + int is the only case that actually requires the type date
. All other expressions in this answer work with date_trunc()
just as well - or even ever so slightly faster.
2.
ts::date + interval '1 day - 1 sec'
date_trunc('day', ts) + interval '1 day - 1 sec'
Postgres interval input allows a single expression with multiple time units. No need for two operations.
3.
date_trunc('day', ts) + interval '23:59:59'
Simpler yet, add the desired time component to the date (or start of the day).
4.
date_trunc('day', ts) + time '23:59:59'
Same thing with type time
.
Last timestamp of the same day
xxxx-xx-xx 23:59:59
is not the "end of the day". The Postgres timestamp
data type (currently, and not likely to change) stores values with microsecond resolution. The latest possible timestamp for a day is xxxx-xx-xx 23:59:59.999999
.
5.
date_trunc('day', ts) + interval '1 day - 1 microsecond'
6.
date_trunc('day', ts) + interval '23:59:59.999999'
7.
date_trunc('day', ts) + time '23:59:59.999999'
This last expression should be fastest besides being correct.
Start of the next day
Typically, operating with the start of the next day as exclusive upper bound is the superior approach. Does not depend on implementation details and is even simpler to generate.
8.
ts::date + 1 -- returns date!
9.
date_trunc('day', ts) + interval '1 day' -- returns timestamp
All work in any version since at least Postgres 8.4. Demo in Postgres 15:
fiddle