Usando la hora actual en UTC como valor predeterminado en PostgreSQL

172

Tengo una columna del TIMESTAMP WITHOUT TIME ZONEtipo y me gustaría tener ese valor predeterminado para la hora actual en UTC. Obtener la hora actual en UTC es fácil:

postgres=# select now() at time zone 'utc';
          timezone          
----------------------------
 2013-05-17 12:52:51.337466
(1 row)

Como está usando la marca de tiempo actual para una columna:

postgres=# create temporary table test(id int, ts timestamp without time zone default current_timestamp);
CREATE TABLE
postgres=# insert into test values (1) returning ts;
             ts             
----------------------------
 2013-05-17 14:54:33.072725
(1 row)

Pero eso usa la hora local. Intentar forzar eso a UTC resulta en un error de sintaxis:

postgres=# create temporary table test(id int, ts timestamp without time zone default now() at time zone 'utc');
ERROR:  syntax error at or near "at"
LINE 1: ...int, ts timestamp without time zone default now() at time zo...
Wichert Akkerman
fuente

Respuestas:

297

Ni siquiera se necesita una función. Simplemente ponga paréntesis alrededor de la expresión predeterminada:

create temporary table test(
    id int, 
    ts timestamp without time zone default (now() at time zone 'utc')
);
Daniel Vérité
fuente
2
Puedo ver una función como now_utc () realmente brilla al escribir consultas
misaxi
Esto incluso funciona cuando el tiempo retrocede una hora: ahora () devuelve una marca de tiempo que conoce el desplazamiento de UTC.
Clay Lenhart
1
Fwiw, ejecución de esta consulta en PostgreSQL 11.5: ALTER TABLE testcase_result ADD COLUMN date_created TIMESTAMP WITHOUT TIME ZONE DEFAULT (NOW() AT TIME ZONE "UTC") NOT NULL;falla con: ERROR: column "UTC" does not exist. Asegúrese de que 'utc'todo sea en minúsculas.
code_dredd
2
Corrección: la 'utc'cadena también debe estar entre comillas simples, no entre comillas dobles.
code_dredd
56

Aún otra solución:

timezone('utc', now())
martti
fuente
26

Envuélvelo en una función:

create function now_utc() returns timestamp as $$
  select now() at time zone 'utc';
$$ language sql;

create temporary table test(
  id int,
  ts timestamp without time zone default now_utc()
);
Denis de Bernardy
fuente
16

Qué pasa

now()::timestamp

Si su otra marca de tiempo no tiene zona horaria, entonces este lanzamiento arrojará el tipo de coincidencia "marca de tiempo sin zona horaria" para la hora actual.

Sin embargo, me gustaría leer lo que otros piensan sobre esa opción. Todavía no confío en mi comprensión de estas cosas de zona horaria "con / sin".

EDITAR: Agregar el comentario de Michael Ekoka aquí porque aclara un punto importante:

Consideración. La pregunta es sobre la generación de la marca de tiempo predeterminada en UTC para una columna de marca de tiempo que no almacena la zona horaria (tal vez porque no hay necesidad de almacenar la zona horaria si sabe que todas sus marcas de tiempo comparten lo mismo). Lo que su solución hace es generar una marca de tiempo local (que para la mayoría de las personas no necesariamente se configurará como UTC) y almacenarla como una marca de tiempo ingenua (una que no especifique su zona horaria).

Risadinha
fuente
Es un truco interesante, pero puede generar confusión a menos que sea consciente de este comportamiento. La respuesta aceptada es clara como el cristal sobre la acción y el resultado deseado. Lo mismo con la función pero me quedo fuera de las funciones de DB ....
Frank V
en mi opción, genera fecha y hora local en db
VelikiiNehochuha
Consideración. La pregunta es sobre la generación de la marca de tiempo predeterminada en UTC para una columna de marca de tiempo que no almacena la zona horaria (tal vez porque no hay necesidad de almacenar la zona horaria si sabe que todas sus marcas de tiempo comparten lo mismo). Lo que su solución hace es generar una marca de tiempo local (que para la mayoría de las personas no necesariamente se configurará como UTC) y almacenarla como una marca de tiempo ingenua (una que no especifique su zona horaria).
Michael Ekoka
@MichaelEkoka He agregado su comentario a la respuesta. Por favor, continúe y edítelo si lo desea. Lo estás explicando muy claramente. ¡Gracias!
Risadinha
Advertencia : una marca de tiempo con un campo de zona horaria NO almacena la zona horaria, en contra de lo que se supone razonablemente. Vea el siguiente enlace y busque la página para UTC. En la entrada, una marca de tiempo con zona horaria convierte el valor entrante a utc y almacena ese valor SIN INFORMACIÓN DE ZONA HORARIA O COMPENSACIÓN . En la salida, el valor utc almacenado se convierte a una hora local utilizando la zona horaria del cliente, si está disponible. Este tipo tiene que ver con la conversión de valor en el momento de la consulta. Debe probar esto almacenando desde una zona horaria y seleccionando desde una diferente. postgresql.org/docs/11/datatype-datetime.html
Tom
7

Estas son 2 soluciones equivalentes:

(en el código siguiente, se debe sustituir 'UTC'por la zona y now()de marca de tiempo )

  1. timestamp AT TIME ZONE zone - SQL-estándar-conforme
  2. timezone(zone, timestamp) - posiblemente más legible

La zona horaria de la función (zona, marca de tiempo) es equivalente a la marca de tiempo de construcción conforme a SQL en la zona de zona horaria.


Explicación:

  • la zona se puede especificar como una cadena de texto (p. ej. 'UTC') o como un intervalo (p. ej., INTERVAL '-08:00'): aquí hay una lista de todas las zonas horarias disponibles
  • la marca de tiempo puede ser cualquier valor de tipo de marca de tiempo
  • now()devuelve un valor de tipo de marca de tiempo (justo lo que necesitamos) con la zona horaria predeterminada de su base de datos adjunta (por ejemplo 2018-11-11T12:07:22.3+05:00).
  • timezone('UTC', now())convierte nuestra hora actual (de tipo marca de tiempo con zona horaria ) en el equivalente sin zona horaria en UTC.
    Por ejemplo, SELECT timestamp with time zone '2020-03-16 15:00:00-05' AT TIME ZONE 'UTC'volveremos 2020-03-16T20:00:00Z.

Documentos: zona horaria ()

Lakesare
fuente
1
Gracias por resumir estas cosas. Utilicé la versión en minúsculas at timezone 'utc'y eso no funcionó con mi configuración de PostgreSQL.
Problema
2

La función ya existe: zona horaria ('UTC' :: texto, ahora ())

usuario10259440
fuente