I was surprised select date_trunc('day','2021-02-16 20:00+04'::timestamptz);
returned 2021-02-17 00:00:00+08
in postgres.
It's like we moved forward in time from 16th to 17th.
I want to check my understanding and find sources explaining this (ideally official).
The session has set timezone = 'Asia/Singapore'; --utc+8
My understanding
There are 2 transformations happening before truncation:
date_trunc
runs, 16:00+00 becomes next day 00:00+08 because date_trunc
interprets in local time (session timezone)I tested the hypothesis by changing input to 2021-02-16 20:00+05
, which outputs 2021-02-16 00:00:00+08
. (no day increment).
I guess this is because the 1st transformtion went backwards 1 more hour to 15:00+00, so the 2nd transformation only reached 11pm of day 16th instead of 12am on 17th?
I couldn't find any docs mentioning this double interpretation behaviour. Closest is below:
When the input value is of type timestamp with time zone, the truncation is performed with respect to a particular time zone; for example, truncation to day produces a value that is midnight in that zone. By default, truncation is done with respect to the current TimeZone setting, but the optional time_zone argument can be provided to specify a different time zone.
https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
What you are seeing:
set timezone = 'Asia/Singapore';
--Casting to timestamptz rotates the timestamp to localtime.
select '2021-02-16 20:00+04'::timestamptz;
timestamptz
------------------------
2021-02-17 00:00:00+08
--Using the returned value from above.
--date_trunc to 'day' lands on Midnight.
select date_trunc('day', '2021-02-17 00:00:00+08'::timestamptz);
date_trunc
------------------------
2021-02-17 00:00:00+08