Generar calendarios con Python es un proyecto práctico para aprender fechas, validación, funciones, archivos y formatos de salida. La biblioteca estándar incluye el módulo calendar, capaz de producir calendarios de texto o HTML sin instalar paquetes adicionales.
Para complementar este proyecto, consulta las guías sobre entrada y salida, funciones, archivos, manejo de errores y diccionarios. Como referencias externas, revisa la documentación oficial de calendar y la documentación oficial de datetime.
Mostrar un mes en la terminal
import calendar
print(calendar.month(2026, 7))
El resultado incluye el nombre del mes, los días de la semana y la distribución de fechas. El primer argumento es el año y el segundo es el mes entre 1 y 12.
Mostrar un año completo
print(calendar.calendar(2026))
Esta función crea una representación de texto de todos los meses. Es útil para consultas rápidas o para exportar un archivo simple.
Validar año y mes
La entrada del usuario llega como texto. Convierte y valida antes de llamar al módulo:
def leer_entero(mensaje, minimo, maximo):
while True:
entrada = input(mensaje).strip()
try:
valor = int(entrada)
except ValueError:
print("Escribe un número entero válido.")
continue
if minimo <= valor <= maximo:
return valor
print(f"El valor debe estar entre {minimo} y {maximo}.")
El mes puede limitarse de 1 a 12. Para el año, define un intervalo razonable según tu aplicación.
Programa interactivo básico
import calendar
def main():
anio = leer_entero("Año: ", 1, 9999)
mes = leer_entero("Mes (1-12): ", 1, 12)
print()
print(calendar.month(anio, mes))
if __name__ == "__main__":
main()
Separar la lectura y la ejecución en funciones facilita pruebas y futuras ampliaciones.
Cambiar el primer día de la semana
Por defecto, muchos calendarios de Python comienzan el lunes. Puedes utilizar una instancia configurada:
calendario = calendar.TextCalendar(firstweekday=calendar.SUNDAY)
print(calendario.formatmonth(2026, 7))
También existe calendar.MONDAY. Elige la convención esperada por tus usuarios y mantenla en toda la aplicación.
Obtener semanas como datos
calendario = calendar.Calendar(firstweekday=calendar.MONDAY)
semanas = calendario.monthdayscalendar(2026, 7)
for semana in semanas:
print(semana)
Cada semana es una lista de siete números. El cero representa una posición perteneciente al mes anterior o siguiente.
Ignorar los ceros
for semana in semanas:
for dia in semana:
if dia == 0:
continue
print(dia)
Este formato permite crear interfaces propias, tablas, agendas o exportaciones.
Nombre del mes y de los días
print(calendar.month_name[7])
print(calendar.day_name[0])
Los nombres dependen de la configuración regional del proceso. No asumas que estarán en español en todos los sistemas.
Localización
Python ofrece calendarios que pueden utilizar configuraciones regionales, pero la disponibilidad de locales depende del sistema operativo. Para una aplicación portable, puedes mantener tus propios nombres:
MESES = {
1: "enero",
2: "febrero",
3: "marzo",
4: "abril",
5: "mayo",
6: "junio",
7: "julio",
8: "agosto",
9: "septiembre",
10: "octubre",
11: "noviembre",
12: "diciembre",
}
Así controlas el idioma sin depender de configuraciones externas.
Comprobar años bisiestos
if calendar.isleap(2028):
print("Es un año bisiesto")
También puedes contar los años bisiestos dentro de un intervalo con leapdays().
Conocer el primer día y la cantidad de días
dia_semana, cantidad = calendar.monthrange(2026, 7)
print(dia_semana, cantidad)
El día de la semana utiliza números de cero a seis, con lunes como cero. La cantidad indica cuántos días tiene el mes.
Crear una lista de fechas reales
from datetime import date
import calendar
def fechas_del_mes(anio, mes):
_, cantidad = calendar.monthrange(anio, mes)
return [date(anio, mes, dia) for dia in range(1, cantidad + 1)]
Los objetos date permiten comparar, ordenar y formatear fechas con seguridad.
Filtrar días laborables
def dias_laborables(anio, mes):
return [
fecha
for fecha in fechas_del_mes(anio, mes)
if fecha.weekday() < 5
]
weekday() devuelve cero para lunes y seis para domingo. Este ejemplo no descuenta festivos.
Añadir eventos
from datetime import date
eventos = {
date(2026, 7, 3): ["Reunión del equipo"],
date(2026, 7, 15): ["Entrega del informe", "Pago"],
}
Un diccionario relaciona fechas con listas de eventos. Usa una lista porque un mismo día puede contener varias actividades.
Mostrar una agenda mensual
def mostrar_agenda(anio, mes, eventos):
for fecha in fechas_del_mes(anio, mes):
actividades = eventos.get(fecha, [])
if actividades:
print(fecha.strftime("%d/%m/%Y"))
for actividad in actividades:
print(f" - {actividad}")
La agenda puede coexistir con la representación visual del calendario.
Guardar el calendario en TXT
from pathlib import Path
contenido = calendar.month(2026, 7)
Path("calendario-2026-07.txt").write_text(contenido, encoding="utf-8")
Utiliza UTF-8 y nombres predecibles. Comprueba antes de sobrescribir un archivo existente si contiene información importante.
Crear HTML
calendario_html = calendar.HTMLCalendar(firstweekday=calendar.MONDAY)
html = calendario_html.formatmonth(2026, 7)
Path("calendario.html").write_text(
"<!doctype html><meta charset='utf-8'>" + html,
encoding="utf-8",
)
El resultado es una tabla HTML básica. Puedes añadir CSS para mejorar la presentación.
Añadir estilos
estilos = """
<style>
table { border-collapse: collapse; font-family: sans-serif; }
th, td { border: 1px solid #999; padding: 10px; text-align: center; }
th { background: #eee; }
</style>
"""
Inserta los estilos en el documento completo. Si los eventos proceden de usuarios, escapa el contenido antes de generar HTML.
Exportar CSV
import csv
with open("agenda.csv", "w", newline="", encoding="utf-8") as archivo:
escritor = csv.writer(archivo)
escritor.writerow(["fecha", "evento"])
for fecha, actividades in sorted(eventos.items()):
for actividad in actividades:
escritor.writerow([fecha.isoformat(), actividad])
El formato ISO AAAA-MM-DD evita ambigüedad y facilita importar los datos en otras herramientas.
No confundir fechas con zonas horarias
Un calendario mensual de días puede usar date. Si añades horas, recordatorios o usuarios de diferentes países, necesitarás objetos con zona horaria y reglas más cuidadosas. No guardes horas locales sin indicar su zona.
Pruebas
def test_febrero_bisiesto():
fechas = fechas_del_mes(2028, 2)
assert len(fechas) == 29
assert fechas[-1].day == 29
def test_febrero_normal():
assert len(fechas_del_mes(2027, 2)) == 28
Prueba meses de 28, 29, 30 y 31 días, límites de año y distintos primeros días de semana.
Errores frecuentes
Los fallos habituales son aceptar meses fuera de 1 a 12, depender de un locale que no existe, confundir el índice del día, interpretar los ceros como fechas reales y mezclar objetos date con strings en las mismas claves.
Ideas para ampliar el proyecto
Añade eventos desde JSON, colores para fines de semana, exportación HTML, navegación entre meses, recordatorios, feriados configurables y una interfaz con Tkinter. Mantén la lógica de fechas separada de la interfaz para poder probarla.
Conclusión
El módulo calendar ofrece tanto representaciones listas para imprimir como datos estructurados para construir calendarios propios. Combínalo con datetime para fechas reales, valida siempre el año y el mes, y utiliza formatos portables para guardar eventos. Este proyecto puede comenzar con tres líneas y crecer hasta una agenda completa sin abandonar la biblioteca estándar.






