I saw similar questions here, e. g. "I want to change time from 13:00 to 17:00" and always answers were "use '13:00' + INTERVAL '4 hours'"
BUT, what I need is to SET the date_part value to existing date, without knowing the exact interval size, something opposite to date_part (extract) function.
For example:
-- NOT A REAL FUNCTION
SELECT date_set('hour', date, 15)
FROM (VALUES ('2021-10-23 13:14:43'::timestamp), ('2020-11-02 10:00:34')) as dates (date)
Which result will be:
2021-10-23 15:14:43
2020-11-02 15:00:34
As you can see, this cannot be done with simple +/- INTERVAL expression.
Possible solution
What I've already found on SO is:
SELECT date_trunc('day', date) + INTERVAL '15 hour'
FROM (VALUES ('2021-10-23 13:14:43'), ('2020-11-02 10:00:34')) as dates (date)
But this variant does not preserve minutes and seconds.
Although, I can fix this issue, simply adding back minutes, seconds and microseconds of original timestamp:
SELECT date_trunc('day', date) + INTERVAL '15 hour'
+ (extract(minute from date) || ' minutes')::interval
+ (extract(microsecond from date) || ' microseconds')::interval
FROM (VALUES ('2021-10-23 13:14:43.001240'::timestamp), ('2020-11-02 10:00:34.000001')) as dates (date)
This will output:
2021-10-23 15:14:43.001240
2020-11-02 15:00:34.000001
And it solves the problem.
But honestly, I'm not very pleased by this solution. Maybe someone knows better variants?