¿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é.
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 pd
pedidos = 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: se guarda tal como la escribiste para compararla. Solo tú y tu Maestro ven tus predicciones.
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 total
FROM pedidos
WHERE 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.
Cuenta los pedidos de marzo de 2026 (en UTC) y suma su total sin perder ningún pedido del día 31.
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 |
Cada ejecución empieza con copias nuevas de las tablas del curso, así que puedes probar lo que quieras. Tab agrega sangría; para salir del editor, presiona Escape y luego Tab.
Listo para ejecutar tu consulta.
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.
Cuenta los pedidos del 31 de marzo de 2026 (en UTC) y suma su total, con un intervalo semiabierto.
Cuenta los pedidos del 31 de marzo de 2026 (en UTC) y suma su total, con un intervalo semiabierto.
Ejecuta tu código para ver lo que imprime y el valor de su última expresión. Cada ejecución empieza de nuevo. Ctrl+Enter ejecuta tu código. Tab agrega sangría; para salir del editor, presiona Escape y luego Tab.
Listo para ejecutar tu código.
Ejecuta tu código para ver su salida aquí.
Datos: pedidos-en-linea, 304 filas
Enter guarda una celda y Escape la deja como estaba. Deja una celda vacía para un valor faltante.
| Fila | Quitar | |||
|---|---|---|---|---|
| 1 | ||||
| 2 | ||||
| 3 | ||||
| 4 | ||||
| 5 | ||||
| 6 | ||||
| 7 | ||||
| 8 | ||||
| 9 | ||||
| 10 | ||||
| 11 | ||||
| 12 | ||||
| 13 | ||||
| 14 | ||||
| 15 | ||||
| 16 | ||||
| 17 | ||||
| 18 | ||||
| 19 | ||||
| 20 |