96 periodos, salvo dos días al año
El fichero del mercado diario trae los precios de la electricidad en periodos
de quince minutos. Un día tiene 24 horas, así que trae 96 valores. Se escribe el
parser, se prueba con el fichero de ayer, con el de la semana pasada y con el de
hace un mes, y los tres traen 96. La constante 96 se cuela en el
código como una verdad del universo.
Y lo es, 363 días al año.
Los dos días raros
El cambio de hora no altera la duración de los periodos: altera la del día. El domingo de marzo en que los relojes se adelantan tiene 23 horas y, por tanto, 92 periodos. El domingo de octubre en que se atrasan tiene 25 y trae 100.
Qué le pasa a un código que asume 96 depende de cómo esté escrito, y las tres variantes son malas:
- Si recorre un rango fijo
range(96), en octubre pierde cuatro periodos —una hora entera de precios, y precisamente la de una madrugada barata— y en marzo revienta o lee basura al pasarse del final. - Si valida
len(datos) == 96y aborta, esos dos días no hay precios. La web enseña los de ayer y nadie se entera hasta que alguien mira. - Si mapea cada periodo a una hora del reloj local, el día largo tiene dos veces las 02:00 y una sobrescribe a la otra.
El arreglo es corto: el número de periodos se cuenta, no se supone, y se acepta cualquiera de los tres valores legítimos rechazando el resto. Y la clave de cada precio no es la hora del reloj —que se repite— sino el índice del periodo dentro de su día, o un instante absoluto en UTC.
PERIODOS_VALIDOS = {92, 96, 100} # 23 h, 24 h y 25 h: los tres días posibles
n = len(precios)
if n not in PERIODOS_VALIDOS:
raise ValueError(f"el fichero trae {n} periodos, ninguno válido")
Regla. Cualquier constante que dependa de «cuántas horas tiene un día» es un fallo con fecha de caducidad conocida. En España, el último domingo de marzo y el último de octubre.
Lo incómodo de este fallo es su cadencia: aparece dos veces al año, dura un día y se cura solo. Es exactamente el perfil de error que nunca llega a diagnosticarse, porque cuando alguien lo mira ya no pasa.
La columna equivocada
Hay una segunda trampa en el mismo fichero. España y Portugal comparten mercado y, la mayoría de los días, comparten precio: el fichero trae una sola serie. Pero cuando la interconexión se satura, el mercado se parte y ese día aparecen dos precios distintos, uno por país.
Un parser que asume una única columna de precios, o que coge siempre la primera, funciona el 90 % de los días y el resto publica precios portugueses en una web española. Sin avisar de nada, porque los números son perfectamente plausibles.
Por eso el fichero de prueba del parser no es un día cualquiera: es deliberadamente un día con el mercado partido. Un test que solo usa días normales no puede detectar el error que importa.
La hora de publicación no existe
El otro problema no es de formato sino de calendario. Los precios del día siguiente se publican por la tarde, tras la casación. La documentación da una hora de referencia y la intuición dice que será estable.
Lo medimos: durante trece días seguidos, la hora a la que el fichero estuvo realmente disponible osciló entre las 13:26 y las 19:38, con una mediana en torno a las 14:00. Sin patrón semanal, sin correlación evidente con nada que pudiéramos observar desde fuera.
Con esa dispersión, programar una descarga a una hora fija es elegir entre dos formas de fallar: temprano, y el fichero aún no está; tarde, y la web pasa la tarde entera enseñando datos viejos. La conclusión práctica es que la hora de publicación no se persigue. Se hace la descarga autorreparable:
- Varios intentos repartidos por la tarde, no uno. Cada ejecución es idempotente: si el dato ya está, no hace nada.
- Un 404 del día siguiente no es un error. Es el estado normal antes de la casación. Se avisa por la salida de diagnóstico, se escribe lo que sí hay —el día en curso— y el proceso termina con éxito. Si el 404 se trata como fallo, el sistema de alertas grita todas las tardes y en dos semanas nadie le hace caso.
- Un fallo nunca pisa un dato bueno. La escritura es atómica —fichero temporal y renombrado— y solo ocurre si hay algo válido que escribir. Si la descarga falla, el fichero anterior se queda intacto y el visitante nunca recibe un JSON a medio escribir.
- La página declara la antigüedad del dato. Si el último precio pasa de dos días, sale un aviso visible en vez de una gráfica que aparenta estar al día.
Regla. Nunca se inventa un precio. Ni interpolando, ni repitiendo el del día anterior, ni «estimando». Un hueco declarado es un dato honesto; un hueco rellenado es una mentira que alguien va a usar para decidir cuándo arrancar una máquina.
Lo que esto le cuesta a un cliente
Nada de lo anterior es exótico y todo se puede resumir en una frase: los datos de mercado son una dependencia externa que ni controlas ni puedes exigir. Todo el diseño consiste en degradar bien cuando esa dependencia no está.
Un sistema que decide cuándo arrancar procesos según el precio de la luz vale exactamente lo que valga su peor día: aquel en el que el fichero llega a las 19:38, viene con 100 periodos y trae dos columnas.
El poso
- Cuenta los periodos, no los supongas. 92, 96 y 100 son todos días legítimos.
- La clave de una serie horaria no puede ser la hora del reloj local: dos días al año esa hora se repite o desaparece.
- Elige los ficheros de prueba por el caso raro que representan, no por comodidad. Un día normal no prueba nada.
- Si la hora de un evento externo varía seis horas, no programes contra la hora: programa reintentos idempotentes y haz que el fallo sea visible en la interfaz.
¿Te suena de tu planta? Esto sale de operar instalaciones reales todos los días. Si tienes un problema parecido, cuéntanoslo: la primera conversación es con un ingeniero, no con un comercial.
Hablar con un ingeniero Probar el simulador →
VOLTIA