¿Por qué BETWEEN pierde el último día? Filtrar fechas con hora
Filtra un día, un mes o una semana completos aunque la columna tenga hora, con un intervalo semiabierto que no pierde el último día.
Curso gratis. Tu Maestro, una IA, .
Los pedidos en línea
Café Altura también vende por internet. La tienda en línea guarda cada pedido en la tabla pedidos: un pedido_id, el momento en que se creó (creado_utc) y el total en pesos. Son 304 pedidos sintéticos de febrero y marzo de 2026.
Esta columna ya es una fecha, no un texto, pero trae algo más: la hora. El primer pedido se creó el 2026-02-01 02:44:40. A una fecha con hora se le llama timestamp, y en DuckDB su tipo es TIMESTAMP.
El nombre de la columna dice utc: esas horas están en UTC, no en la hora de Ciudad de México. Eso lo resuelves en la siguiente lección. Aquí el problema es otro, y aparece aunque todo estuviera en tu hora local. Predice.
Cuatro pedidos de fin de marzo, con hora, y dos maneras de quedarte con los de marzo. Escribe qué crees que imprime cada programa y por qué.
Marzo con <= '2026-03-31'
Ejemplo 1 de 2
import pandas as pdpedidos = pd.Series(pd.to_datetime([ "2026-03-30 18:05", "2026-03-31 00:00", "2026-03-31 09:15", "2026-03-31 21:40",]))de_marzo = pedidos[(pedidos >= "2026-03-01") & (pedidos <= "2026-03-31")]print(len(de_marzo))Adivinar está bien. Lo que escribas se queda en este navegador y te espera en tu curso.
Ejemplo 2 de 2, se abre cuando expliques este
Una fecha sola es la medianoche
Cuando comparas un timestamp con una fecha sin hora, la fecha vale lo mismo que su primer instante: '2026-03-31' es 2026-03-31 00:00:00. Con eso se explican tres errores comunes:
BETWEEN '2026-03-01' AND '2026-03-31'incluye sus dos extremos, pero el extremo final es la medianoche del 31. Enpedidoscuenta 154 pedidos y 33,469 pesos. Marzo tuvo 159 pedidos y 34,630 pesos en UTC.creado_utc = '2026-03-31'busca pedidos creados exactamente a las 00:00:00. Hubo 5 pedidos ese día y el filtro encuentra 0.<= '2026-03-31 23:59:59'parece arreglarlo, pero deja fuera lo que pase después del último segundo entero, si tus datos guardan fracciones de segundo.
Si no ves por qué BETWEEN pierde el 31, pregúntale a tu Maestro con tus palabras.
El intervalo semiabierto
La forma que no falla es un intervalo semiabierto: desde el primer instante del periodo, incluido, hasta el primer instante del periodo siguiente, sin incluirlo.
creado_utc >= '2026-03-01' AND creado_utc < '2026-04-01'
Funciona igual para un día (>= '2026-03-31' AND < '2026-04-01'), una semana o un año, y no depende de cuántos días tiene el mes ni de cuántos decimales trae la hora.
Compara la columna con dos textos de fecha y une las condiciones con &, cada una entre paréntesis:
marzo = data[(data["creado_utc"] >= "2026-03-01") & (data["creado_utc"] < "2026-04-01")]Series.between("2026-03-01", "2026-03-31") tiene el mismo problema que BETWEEN: en pedidos cuenta 154.
SELECT count(*) AS pedidos, sum(total) AS totalFROM pedidosWHERE creado_utc >= '2026-03-01' AND creado_utc < '2026-04-01';Otra salida que funciona para días completos es quitarle la hora a la columna antes de comparar: creado_utc::DATE BETWEEN '2026-03-01' AND '2026-03-31' también cuenta 159.
Inténtalo
La consulta de abajo usa BETWEEN y pierde pedidos. Cámbiala por un intervalo semiabierto. Una buena respuesta tiene una fila: 159 pedidos y 34,630 pesos.
Tu turno
Cuenta los pedidos de marzo de 2026 (en UTC) y suma su total sin perder ningún pedido del día 31.
Tablas: pedidos (pedido_id, creado_utc, total)
pedidos · 304 filas
| Columna | Tipo |
|---|---|
| pedido_id | BIGINT |
| creado_utc Cuándo se hizo el pedido, en UTC, como lo guarda la tienda en línea. | TIMESTAMP |
| total Total del pedido en pesos. | BIGINT |
Primeras filas
| pedido_id | creado_utc | total |
|---|---|---|
| 5001 | 2026-02-01T02:44:40Z | 89 |
| 5002 | 2026-02-01T02:54:59Z | 420 |
| 5003 | 2026-02-01T15:15:38Z | 89 |
Tab agrega sangría; Esc y Tab para salir
Inténtalo sin ayuda
Ahora en pandas: cuenta los pedidos del 31 de marzo de 2026, en UTC, y suma su total. Usa un intervalo semiabierto de un día. Una buena respuesta cuenta 5 pedidos. Si te sale 0, pégale tu código a tu Maestro.
Tu turno
Cuenta los pedidos del 31 de marzo de 2026 (en UTC) y suma su total, con un intervalo semiabierto.
Datos: pedidos-en-linea, 304 filas
| Fila | Quitar | |||
|---|---|---|---|---|
| 1 | ||||
| 2 | ||||
| 3 | ||||
| 4 | ||||
| 5 | ||||
| 6 | ||||
| 7 | ||||
| 8 | ||||
| 9 | ||||
| 10 | ||||
| 11 | ||||
| 12 | ||||
| 13 | ||||
| 14 | ||||
| 15 | ||||
| 16 | ||||
| 17 | ||||
| 18 | ||||
| 19 | ||||
| 20 |
Enter guarda; Esc deshace; vacía es un valor faltante
Tab agrega sangría; Esc y Tab para salir
Comprueba lo que sabes: ¿Cuál de estos filtros cuenta todos los pedidos del 15 de marzo de 2026, a cualquier hora?