HOWTO · PostgreSQL
Cómo usar la hora actual UTC como valor predeterminado en PostgreSQL
Aprende cómo obtener la hora actual en UTC y usarla como valor predeterminado de una columna de PostgreSQL.
En esta página
Para obtener la hora actual como lectura de reloj en UTC en PostgreSQL, usa now() AT TIME ZONE 'UTC'. Para asignar esa lectura a una columna timestamp without time zone cuando una inserción omita la columna, usa la misma expresión como DEFAULT. El valor contiene una fecha y una hora, pero no incluye un indicador de zona. Si la columna debe representar un instante, usa timestamp with time zone.
Los ejemplos SQL siguientes son ilustrativos y no se ejecutaron en un servidor PostgreSQL. El ejemplo de Python muestra de forma determinista cómo representar una lectura de reloj en UTC; no se conecta a PostgreSQL.
Obtener la hora actual en UTC en PostgreSQL
Ejecuta SELECT now() AT TIME ZONE 'UTC'; para obtener una lectura de reloj en UTC. now() en PostgreSQL devuelve la hora de inicio de la transacción actual, por lo que las llamadas repetidas dentro de una misma transacción devuelven el mismo instante. La operación AT TIME ZONE convierte ese instante de tipo timestamp with time zone en un valor timestamp without time zone, cuyos campos de fecha y hora corresponden a UTC. El resultado no lleva asociada ninguna zona ni desplazamiento.
En cambio, SELECT now(); devuelve un valor timestamp with time zone. PostgreSQL muestra ese instante según la zona horaria de la sesión, pero la representación no cambia el instante. Un valor timestamp without time zone solo almacena los campos de calendario y hora: no contiene metadatos de zona horaria ni de desplazamiento UTC y no es UTC por naturaleza. Úsalo para lecturas en UTC solo si la aplicación y la base de datos coinciden en ese significado.
Establecer un valor predeterminado UTC para una columna de tabla
Para una columna destinada a guardar lecturas de reloj en UTC, defínela como timestamp without time zone con DEFAULT (now() AT TIME ZONE 'UTC'). Por ejemplo, la expresión SQL sería CREATE TABLE event_log (created_at timestamp without time zone DEFAULT (now() AT TIME ZONE 'UTC'), event_name text);. Los paréntesis alrededor de la expresión predeterminada son opcionales.
Inserta una fila omitiendo created_at, por ejemplo con INSERT INTO event_log (event_name) VALUES ('started');, y PostgreSQL evaluará el valor predeterminado de esa columna. Si se proporciona un valor explícito para created_at, este tiene prioridad. El valor predeterminado se aplica al insertar; no actualiza la columna automáticamente después. Como now() queda fijado al inicio de la transacción, las filas insertadas en una misma transacción reciben la misma marca de tiempo. Para datos de eventos que deban representar un instante entre distintos clientes, timestamp with time zone suele ser el tipo más adecuado; cada sesión puede mostrar ese instante en su propia zona horaria.
Convertir la hora actual a UTC
La forma equivalente con la función es timezone('UTC', now()). timezone() de PostgreSQL acepta una zona y un valor de marca de tiempo; con now(), devuelve un timestamp without time zone que muestra el instante en UTC. Se trata de una conversión de marca de tiempo, no de una conversión al tipo TIME. La forma AT TIME ZONE deja visible en la expresión la dirección de la conversión.
Un instante fijo permite ver con claridad la diferencia entre un instante y una lectura de reloj en UTC. Esta ilustración en Python usa la biblioteca estándar e imprime una marca de tiempo sin el indicador de zona:
from datetime import datetime, timezone
instant = datetime(2026, 10, 23, 12, 0, tzinfo=timezone.utc)
utc_clock_reading = instant.astimezone(timezone.utc).replace(tzinfo=None)
print(utc_clock_reading.isoformat(sep=" "))
2026-10-23 12:00:00
Este ejemplo ilustra la forma del valor que produce la expresión SQL; el código Python no ejecuta SQL. No uses now()::timestamp como sustituto de una conversión a UTC: al convertir un valor timestamp with time zone a timestamp without time zone, se usa la zona horaria de la sesión, por lo que los campos de hora dependen de ese ajuste. La forma con intervalo, timezone(INTERVAL '+00:00', now()), también usa un desplazamiento cero y produce la lectura de reloj en UTC. Un desplazamiento distinto de cero, como INTERVAL '-08:00', representa otra lectura de reloj.
Usar una función SQL para un valor predeterminado UTC reutilizable
Si varias definiciones de tablas necesitan la misma expresión, una función SQL opcional permite asignarle un nombre reutilizable. Defínela para que devuelva timestamp without time zone: CREATE FUNCTION current_utc_timestamp() RETURNS timestamp without time zone LANGUAGE sql STABLE AS 'SELECT now() AT TIME ZONE ''UTC''';. Después, usa DEFAULT current_utc_timestamp() en la definición de una columna.
La función agrupa la expresión; no hace que el reloj avance dentro de una transacción ni cambia el tipo devuelto. Al igual que con el valor predeterminado directo, una columna que usa esta función recibe el valor al insertar una fila, y solo si la inserción no proporciona un valor para esa columna. Elige el tipo según el significado de los datos: usa timestamp without time zone para una lectura de reloj en UTC cuyo significado UTC se mantiene por convención, y, por lo general, timestamp with time zone para almacenar un instante.