Vi preguntas similares aquí, por ejemplo, "Quiero cambiar la hora de 13:00 a 17:00" y las respuestas siempre fueron "usar '13:00' + INTERVAL '4 hours' "
PERO, lo que necesito es ESTABLECER el valor de date_part en la fecha existente, sin saber el tamaño exacto del intervalo, algo opuesto a date_part ( extract ).
Por ejemplo:
-- 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)Cual resultado sera:
2021-10-23 15:14:43 2020-11-02 15:00:34 Como puede ver, esto no se puede hacer con una simple expresión +/- INTERVAL .
Lo que ya he encontrado en SO es:
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)Pero esta variante no conserva minutos y segundos.
Aunque puedo solucionar este problema, simplemente agregando minutos, segundos y microsegundos de la marca de tiempo original:
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)Esto generará:
2021-10-23 15:14:43.001240 2020-11-02 15:00:34.000001Y resuelve el problema.
Pero, sinceramente, no estoy muy satisfecho con esta solución. ¿Quizás alguien conoce mejores variantes?
La idea detrás de la siguiente función es borrar la unidad (restar el intervalo correspondiente) y agregar un intervalo dado.
create or replace function timestamp_set(unit text, tstamp timestamp, num int) returns timestamp language sql immutable as $$ select tstamp+ (num- date_part(unit, tstamp))* format('1 %s', unit)::interval $$;Cheque:
select date, timestamp_set('hour', date, 15) as hour_15, timestamp_set('min', date, 33) as min_33, timestamp_set('year', date, 2022) as year_2022 from ( values ('2021-10-23 13:14:43'::timestamp), ('2020-11-02 10:00:34') ) as dates (date) date | hour_15 | min_33 | year_2022 ---------------------+---------------------+---------------------+--------------------- 2021-10-23 13:14:43 | 2021-10-23 15:14:43 | 2021-10-23 13:33:43 | 2022-10-23 13:14:43 2020-11-02 10:00:34 | 2020-11-02 15:00:34 | 2020-11-02 10:33:34 | 2022-11-02 10:00:34 (2 rows)Pruébalo en db<>fiddle.
No hay una función para establecer una parte específica de una marca de tiempo, pero puede usar la aritmética de fecha/hora para producir el resultado que desea. Por ejemplo:
select d + (15 - extract(hour from d)) * interval '1 hour' from datesResultado:
?column? ------------------------ 2021-10-23T15:14:43.000Z 2020-11-02T15:00:34.000ZVer ejemplo de ejecución en DB Fiddle .
SELECT to_timestamp(to_char(ts, 'YYYY-MM-DD 15:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') as fixed_time FROM (VALUES ('2021-10-23 13:14:43'::timestamp), ('2020-11-02 10:00:34'::timestamp)) as dates (ts); 2021-10-23 15:14:43.000000 +00:00 2020-11-02 15:00:34.000000 +00:00