sql >> Base de Datos >  >> RDS >> PostgreSQL

Resta horas de la función now()

Respuesta para timestamp

Debe comprender la naturaleza de los tipos de datos timestamp (timestamp without time zone ) y timestamptz (timestamp with time zone ). Si no lo hace, lea esto primero:

  • Ignorar las zonas horarias por completo en Rails y PostgreSQL

El AT TIME ZONE construct transforma una timestamp a timestamptz , que es casi seguro el movimiento equivocado para su caso:

where eventtime at time zone 'CET' between '2015-06-16 06:00:00'
                                       and '2015-06-17 06:00:00'

Primero , mata el rendimiento. Aplicando AT TIME ZONE a la columna eventtime hace que la expresión no se pueda sargable . Postgres no puede usar índices simples en eventtime . Pero incluso sin índice, las expresiones sargables son más baratas. Ajuste los valores de filtro en lugar de manipular cada valor de fila.
Usted podría compense con un índice de expresión coincidente, pero probablemente sea solo un malentendido y esté mal de todos modos.

¿Qué sucede en esa expresión?

  1. AT TIME ZONE 'CET' transforma la timestamp valor eventtime a timestamptz agregando la compensación horaria de su zona horaria actual. Al usar una zona horaria nombre (no es un desplazamiento numérico ni una abreviatura), esto también tiene en cuenta las reglas de DST (horario de verano), por lo que obtiene un desplazamiento diferente para las marcas de tiempo de "invierno". Básicamente obtienes la respuesta a la pregunta:

    ¿Cuál es la marca de tiempo UTC correspondiente para la marca de tiempo dada en la zona horaria dada?

    Al mostrar el resultado para el usuario se formatea como marca de tiempo local con el desfase horario correspondiente a la zona horaria actual de la sesión. (Puede o no ser el mismo que el utilizado en la expresión).

  2. Los literales de cadena del lado derecho no tienen ningún tipo de datos, por lo que el tipo se deriva de la asignación en la expresión. Ya que eso es timestamptz ahora, ambos se envían a timestamptz , asumiendo la zona horaria actual de la sesión.

    ¿Cuál es la marca de tiempo UTC correspondiente para la marca de tiempo dada para la configuración de zona horaria de la sesión actual?

    El desplazamiento puede variar según las reglas del horario de verano.

En pocas palabras , si siempre operar con la misma zona horaria:CET o 'Europe/Berlin' - Lo mismo para las marcas de tiempo actuales, pero no para las históricas o (posiblemente) futuras, simplemente puede cortar la corteza.

El segundo problema con la expresión:BETWEEN casi siempre está mal con timestamp valores. Ver:

  • Optimizar ENTRE declaraciones de fecha
  • Encuentre rangos de fechas superpuestos en PostgreSQL
SELECT date_trunc('hour', eventtime) AS hour
     , count(DISTINCT serialnumber)  AS ct  -- sure you need distinct?
FROM   t_el_eventlog
WHERE  eventtime >= now()::date - interval '18 hours'
AND    eventtime <  now()::date + interval '6 hours'
AND    sourceid  =  44  -- don't quote the numeric literal
GROUP  BY 1
ORDER  BY 1;

now() es la implementación de Postgres del estándar SQL CURRENT_TIMESTAMP . Ambos devuelven timestamptz (no timestamp !). Puede usar cualquiera.
now()::date es equivalente a CURRENT_DATE . Ambos dependen de la configuración de la zona horaria actual.

Deberías tener un índice de la forma:

CREATE INDEX foo ON t_el_eventlog(sourceid, eventtime)

O bien, para permitir exploraciones de solo índice:

CREATE INDEX foo2 ON t_el_eventlog(sourceid, eventtime, serialnumber)

Si opera en diferentes zonas horarias, las cosas se complican y debe usar timestamptz para todo.

Alternativa para timestamptz

Antes de la actualización de la pregunta, parecía que las zonas horarias importaban. Cuando se trata de diferentes zonas horarias, "hoy" es una dependencia funcional de la zona horaria actual. La gente tiende a olvidar eso.

Para trabajar solo con la configuración de zona horaria actual de la sesión, use la misma consulta que la anterior. Si se ejecuta en una zona horaria diferente, los resultados son incorrectos en realidad. (También se aplica a lo anterior).

Para garantizar un resultado correcto para una zona horaria determinada ('Europa/Berlín' en su caso) independientemente de la configuración de zona horaria actual de la sesión, utilice esta expresión en su lugar:

    ((now() AT TIME ZONE 'Europe/Berlin')::date - interval '18 hours')
            AT TIME ZONE 'Europe/Berlin'  -- 2nd time to convert back

Tenga en cuenta que AT TIME ZONE la construcción devuelve timestamp para timestamptz entrada y viceversa.

Como se mencionó al principio, todos los detalles sangrientos aquí:

  • Ignorar las zonas horarias por completo en Rails y PostgreSQL