Escribí una entidad Java simple con dos campos instantáneos:
@Entity @Table(name = "tb_foo") public class Foo { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(columnDefinition = "TIMESTAMP WITHOUT TIME ZONE") private Instant date1; @Column(columnDefinition = "TIMESTAMP WITHOUT TIME ZONE") private Instant date2; ...Luego escribí un import.sql simple en la carpeta raíz de recursos del proyecto para probar si UTC/Local está funcionando:
INSERT INTO tb_foo (date1, date2) VALUES ('2020-07-22T20:50:01.12345Z', NOW());Como mi zona horaria local es GMT-3, las 20:50:01 anteriores deberían aparecer en el cliente como 17:50:01, y NOW() debería aparecer equivalente a mi hora local (alrededor de las 0:25 en el momento en que probé ). Lo probé en la base de datos H2 y funcionó perfectamente:
Este es el DDL & INSERT auto generado por JPA a H2:
create table tb_foo ( id bigint generated by default as identity, date1 TIMESTAMP WITHOUT TIME ZONE, date2 TIMESTAMP WITHOUT TIME ZONE, primary key (id) ) INSERT INTO tb_foo (date1, date2) VALUES ('2020-07-22T20:50:01.12345Z', NOW())Sin embargo, cuando probé los mismos códigos Java y SQL en Postgres (12.x), no funcionó (20 h UTC se mostró como 20 en lugar de 17):
Este es el DDL & INSERT generado automáticamente por JPA para Postgresql:
create table tb_foo ( id int8 generated by default as identity, date1 TIMESTAMP WITHOUT TIME ZONE, date2 TIMESTAMP WITHOUT TIME ZONE, primary key (id) ) INSERT INTO tb_foo (date1, date2) VALUES ('2020-07-22T20:50:01.12345Z', NOW())¿Qué me perdí?
Actualizar:
Hice otra prueba: escribí otra inserción de base de datos a través de Java (no SQL INSERT):
Foo foo = new Foo(null, Instant.parse("2020-07-23T20:50:01Z"), Instant.now()); fooRepository.save(foo);¡Y la marca de tiempo UTC literal 20:50 se insertó correctamente en Postgresql esta vez! ¡Apareció a las 17:50 en el cliente pgadmin! Así que tal vez la pregunta correcta es:
¿Cómo especificar correctamente una marca de tiempo UTC literal a Postgresql en una llamada SQL INSERT para almacenarla en una marca de tiempo SIN zona horaria?
Lo he probado de dos formas:
INSERT INTO tb_foo (date1, date2) VALUES ('2020-07-22T20:50:01.12345Z', NOW()); INSERT INTO tb_foo (date1, date2) VALUES ('2020-07-22 20:50:01 +00', NOW());Y ambos no funcionaron (ambos muestran 20:50 en lugar de 17:50 en el cliente pgadmin en un sistema GMT-03).
Probablemente debido a: si se especifica una zona horaria en la entrada de tiempo sin zona horaria , se ignora en silencio. Ignora su 'Z' e inserta la fecha y hora tal como se presenta.
Entiendo. Para especificar un literal de marca de tiempo UTC en un SQL INSERT para trabajar en un campo de marca de tiempo de Postgresql SIN zona horaria, primero debe declarar TIMESTAMP WITH TIME ZONE :
INSERT INTO tb_foo (date1, date2) VALUES (TIMESTAMP WITH TIME ZONE '2020-07-23 20:50:01.12345+00', NOW());o
INSERT INTO tb_foo (date1, date2) VALUES (TIMESTAMP WITH TIME ZONE '2020-07-23T20:50:01.12345Z', NOW());Eso también funcionó para la base de datos H2. Entonces, esta es una forma de proporcionar un script SQL que funcione para ambas bases de datos.