Rangos de fechas, intervalos y zona horaria
IntermedioPara filtrar un período sobre una columna con hora, usa un rango semiabierto: incluye el inicio (>=) y excluye el día siguiente al final (<). interval suma o resta tiempo (fecha + INTERVAL '1 month'). AT TIME ZONE convierte a la hora local cuando el «día» o el «mes» del negocio no es el de UTC.
Sintaxis
WHERE fecha_hora >= '2025-08-01'
AND fecha_hora < '2025-09-01'
WHERE fecha_hora >= DATE '2025-08-01'
AND fecha_hora < DATE '2025-08-01' + INTERVAL '1 month'
WHERE fecha_hora AT TIME ZONE 'America/Argentina/Buenos_Aires' >= '2025-08-01'Ejemplo
SELECT
sum(CASE WHEN t.created_at BETWEEN '2025-08-01' AND '2025-08-31'
THEN 1 ELSE 0 END) AS con_between,
sum(CASE WHEN t.created_at >= '2025-08-01' AND t.created_at < '2025-09-01'
THEN 1 ELSE 0 END) AS agosto_utc,
sum(CASE WHEN t.created_at >= DATE '2025-08-01'
AND t.created_at < DATE '2025-08-01' + INTERVAL '1 month'
THEN 1 ELSE 0 END) AS agosto_con_interval,
sum(CASE WHEN t.created_at AT TIME ZONE 'America/Argentina/Buenos_Aires' >= '2025-08-01'
AND t.created_at AT TIME ZONE 'America/Argentina/Buenos_Aires' < '2025-09-01'
THEN 1 ELSE 0 END) AS agosto_hora_argentina
FROM transactions AS t
WHERE t.currency = 'ARS';Resultado
| con_between | agosto_utc | agosto_con_interval | agosto_hora_argentina |
|---|---|---|---|
| 361 | 368 | 368 | 371 |
Cómo leerlo
Son cuatro formas de contar los movimientos en pesos argentinos de agosto de 2025. BETWEEN da 361 porque su extremo final es el 31 a las 00:00 y pierde casi todo ese día. El rango semiabierto y su versión con interval dan 368: el mes completo en UTC. Con la hora de Buenos Aires (UTC−3) son 371, porque el mes local empieza y termina tres horas más tarde. Cuál es el correcto depende de qué «agosto» pidió el negocio.
Error común
Así no
SELECT count(*)
FROM transactions AS t
WHERE t.currency = 'ARS'
AND t.created_at <= '2025-08-31 23:59:59';Corregir el BETWEEN escribiendo 23:59:59 como hora final. Deja fuera lo que ocurre en el último segundo (por ejemplo, 23:59:59.5) y hay que recordar cuántos días tiene cada mes. El rango semiabierto < '2025-09-01' no depende de la precisión de la hora ni del largo del mes.
En otros motores: SQL Server, Snowflake, MySQL, BigQuery
SQL ServerSnowflake
Suman tiempo con
DATEADD(parte, cantidad, fecha). SQL Server no acepta+ INTERVAL; Snowflake acepta las dos formas.DATEADD(month, 1, '2025-08-01')MySQLBigQuery
Usan
DATE_ADDcon un intervalo sin comillas. En BigQuery,DATE_ADDtrabaja conDATE; para unTIMESTAMPse usaTIMESTAMP_ADD, que solo acepta unidades hastaDAY.DATE_ADD(fecha, INTERVAL 1 MONTH)SQL Server
También tiene
AT TIME ZONE(desde 2016), pero con los nombres de zona de Windows, no los de la base IANA comoAmerica/Argentina/Buenos_Aires.created_at AT TIME ZONE 'Argentina Standard Time'BigQuery
Para obtener el día local de un
TIMESTAMPse pasa la zona como segundo argumento deDATE.DATE(created_at, 'America/Argentina/Buenos_Aires')
Estos fragmentos no se ejecutan en el curso: se muestran como referencia de cada motor.