¡Vaya lio! ¿qué hora es? ...o de cómo manejar las horas entre postgresql y Xojo

¡Hola!

Llevo varios días intentando entender esto.

Por una parte estoy usando PostgreSQL para almacenar los datos. Estos los visualizo con Xojo, pero cuando de quiere mostrar las horas…¡sorprende!

Por ello, me he ocupado un momento para entenderlo bien, y quiero compartirlo con vosotros.

Teniendo campos/columnas donde se auto-introduce la fecha en pgsql con la función now(), según el comando usado se muestran distintas horas

Así, a las 10 de la mañana:

PgSQL (tipo) Comando Resultado (en Xojo)
timestamptz to_char(fecha, ‘HH24:MI’) as hora 09:00
timestamp to_char(fecha, ‘HH24:MI’) as hora 09:00
timestamptz to_char(fecha at time zone ‘Europe/Madrid’, ‘HH24:MI’) as hora 10:00
timestamp to_char(fecha at time zone ‘Europe/Madrid’, ‘HH24:MI’) as hora 09:00

La configuración en el servidor (Linux) donde está instalado pgSQL es:

timedatectl
Local time: mar 2024-03-05 10:00:00 CET
Universal time: mar 2024-03-05 09:00:00 UTC
RTC time: mar 2024-03-05 09:00:00
Time zone: Europe/Madrid (CET, +0100)
System clock synchronized: yes
systemd-timesyncd.service active: yes
RTC in local TZ: no

Y de pgSQL

show timezone;
TimeZone
Etc/UTC
(1 row)

Es interesante, cuando menos, que el resultado correcto sea aplicando la zona horaria 2 veces (en el servidor y en Xojo). Afortunadamente, no tenemos cambio de zona, pero ¿qué ocurriría en otros sitios donde una misma provincia/estado/… tiene cambio de zona horaria?

Ahí lo dejo para quien pueda resultar interesante, o tal vez si alguien se le ocurre qué configuración tengo mal…¡estoy a tiempo de cambiar!

:face_with_monocle:

You should stick using UTC in the server, and normalize all your parameters to UTC before sending to it, and converting all values read from it to local time (at the frontend, not in the server).

Backend UTC, Frontend any TZ converting to/from UTC to talk to the backend.

Prefer timestamptz to avoid errors mixing local time with the server time.

XOJO should have a Datetime.SQLDateTimeTZ function to obtain a complete correct ISO8601 string as

2019-09-03 13:39:16.000+01:00


Deberías seguir usando UTC en el servidor y normalizar todos sus parámetros a UTC antes de enviarlos y convertir todos los valores leídos a la hora local (en el frontend, no en el servidor)

Backend UTC, Frontend cualquier TZ que se convierta hacia/desde UTC para comunicarse con el backend.

Prefiera timestamptz para evitar errores mezclando la hora local con la hora del servidor.

XOJO debería tener una función Datetime.SQLDateTimeTZ para obtener una cadena ISO8601 completa y correcta como:

2019-09-03 13:39:16.000+01:00

1 Like

¿Estás usando el comando mostrado en la columna ‘Comando’ para hacerle llegar a Xojo un String?

Como estás en una Zona Horaria +1 la hora en UTC es 09:00. Tu primer comando con timestamptz omite el Time Zone así que el resultado es la hora en UTC, es decir 09:00.
Tu segundo comando tampoco tiene Time Zone, la hora es 09:00
Tu tercer comando ya usa el Time Zone y obtienes la hora que deseas 10:00
Tu tercer comando lo único que hace es usar una hora sin Time Zone y asignar el Time Zone, no convierte/ajusta la hora al nuevo Time Zone por lo que se queda en las 09:00 (no soy experto pero según veo la info aquí)

Si necesitas hora que se ajusten al Time Zone debes usar el tipo ‘timestamptz’ y así tus fechas/horas estarán en UTC (como recomienda Rick) y ya puedes hacer los ajustes en Postgres (como usaste el comando para asignar el Time Zone) o le indicas a Xojo al construir tu DateTime que Time Zone es el que quieres usar.

El tipo timestamptz se recomienda cuando debes ajustar la fecha/hora a la zona horaria de la persona que usa tu sistema.
El tipo timestamp se recomienda cuando la fecha/hora normalmente no se ajusta (por ejemplo en la fecha de nacimiento, no por nacer en México a las 8pm del día 15-enero-1980 tengo que poner en España que el nacimiento fue el 16-enero-1980 a las 2am).

Espero esta información sea clara.


Si ejecutas SHOW TIMEZONE; en tu Postgres, ¿qué resultado te muestra?

hummmm…

Thank you. I have to plan this as an idea as far as I use this server for other jobs, mainly cron/bash based, so I update and set the info on this server (mainly working as a database server) from/to other servers

So,I guess try this idea will give me some more work.


Gracias! Tendré que pensar en ello, pero lo tomo como idea en tanto que uso este servidor para otras tareas, principalmente via cron/bash de tal forma que uso la información de este servidor (que está trabajando, principalmente como servidor de bases de datos) con otros servidores.

Por lo que me temo que implementar esta idea puede darme más trabajo

Efectivamente, los comandos bajo la columna “Comando” son los que envío desde Xojo para pedir los datos que pasan a un listado siendo texto. He optado por dejar que el servidor manipule los datos, antes que Xojo porque, en algún caso, ya me he dado cuenta que el tiempo de respuesta entre enviar la petición y mostrar los datos es menor que si se procesan los datos con Xojo (formato, cálculos…)

Por otra parte (y según estoy recordando ahora) hay otra situación, que creo no tendría que afectar, pero por considerar todo, es la hora de verano/invierno ( Daylight saving time)

SHOW TIME en el servidor devuelve Europe/Paris…pero como me gusta aprender y probar, vi que usando Europe/Madrid me daba el mismo resultado

Entonces Xojo no te está cambiando las horas, así es como las entrega Postgres. No estaba del todo claro, gracias.

Mientras uses el tipo ‘timestamptz’ y pidas la hora con el comando con la zona que quieres, no debe haber problema.

¿Usaste ‘SHOW TIME’ o ‘SHOW TIMEZONE’?
¿Europe/Paris te lo da el servidor Linux o Postgres?

En nuestro caso tenemos el servidor configurado con Zona America/Chicago y al ejecutar ‘SHOW TIMEZONE;’ en el Postgres responde con Etc/UTC

Entonces Xojo no te está cambiando las horas, así es como las entrega Postgres. No estaba del todo claro, gracias.

¿Usaste ‘SHOW TIME’ o ‘SHOW TIMEZONE’?

perdón. Error al escribir.
Para tenerlo comparativo

desde psql usando SHOW TIMEZONE; desde bash usando timedatectl
TimeZone Local time: mié 2024-03-06 10:31:45 CET
Etc/UTC Universal time: mié 2024-03-06 09:31:45 UTC
(1 row) RTC time: mié 2024-03-06 09:31:45
Time zone: Europe/Madrid (CET, +0100)

teniendo en cuenta que
(resultados desde psql usando \d+ mitabla)

Column Type Collation Nullable Default
ordenfechaalta timestamp with time zone not null now()

Por último

Mientras uses el tipo ‘timestamptz’ y pidas la hora con el comando con la zona que quieres, no debe haber problema.

select to_char(ordenfechaalta,‘HH24:MI’) from ordenes order by ordenfechaalta desc limit 1;
to_char

09:27
(1 row)

cuando debiera poner 10:27

Hola Alberto, tal vez todavía no te queda claro lo de las horas.

Intentaré otra vez desde el inicio, tu mensaje original indicaba:

Como por defecto (default) tu PgSQL está en

las horas se guardan como UTC, es decir, a las 10am local la base de datos lo guarda como las 9am UTC.

  • Entonces tu primer prueba, le pides a un campo timestamptz que te de la hora sin zona horaria (timezone) por lo que te da lo que tiene que son 09:00
  • Segundo comando, un campo sin tz, le pides la hora y te da las 09:00
  • Tercer comando, un campo con tz, le pides la hora y le indicas que la quieres para la zona de Madrid, arrojando las 10:00 como debe ser, si usaras otra zona horaria te daría la hora correcta, por ejemplo hora del centro de USA indicaría 03:00
  • Cuarto comando, un campo sin tz, le pides la hora y te la da como 09:00 ya que eso tiene y no la puede convertir porque no maneja el cambio zonas horarias. Si le pusieras cualquier otra zona horaria, siempre indicaría 09:00

Ese no es el comando necesario ya que le falta la zona horaria que quieres, ese comando lo pide sin zona horaria por lo que te regresará la hora en UTC, en este caso 09:27.

Debes usar el comando to_char(fecha at time zone ‘Europe/Madrid’, ‘HH24:MI’)

Espero que ahora ya esté claro por qué tu servidor Postgres guarda las 09:00 y no las 10:00 y cómo puedes hacer que te devuelva la hora que tu quieres.


Otro opción, pero no recomendada, es que cambies el Time Zone a tu servidor Postgres.

Lo mejor es entender lo que está pasando, que la base de datos está mejor en UTC y que para tener la hora de tu zona debes ejecutar el to_char informando la zona que quieras.

Si todavía no queda claro, dime y veo si lo puedo explicar mejor.

Saludos

1 Like

¡Gracias!

Finalmente, observo, la orden tiene que ser como me confirmas, pero el primer pensamiento es que si se pone tz no tuviera que ser necesario volver a indicar la zona horaria…

Ciertamente, lo que aclara es saber que el tz lo que hace, principalmente, es almacenar la información para que luego se pueda manipular.

1 Like