Módulo 5: Scheduling y Tiempo
Business Days y Calendarios Fiscales
Descripción de la cápsula
Negocios reales operan en días hábiles — lunes a viernes, excluyendo holidays. "Procesar facturas el día 5 de cada mes" debería significar "5 si es laboral, próximo laboral si es fin de semana o holiday". "Esperar 3 días hábiles" no significa 72 horas — significa saltar fines de semana y feriados.
Cron no maneja esto. Necesitas lógica en el workflow que sepa el calendario fiscal de tu país/región. En esta cápsula vas a aprender los patterns para business days, cómo manejar holidays (con APIs o Sheets manuales), y casos típicos de calendarios fiscales (cierre de mes, trimestre, año fiscal).
Lo que vas a aprender
- ✅ Calcular días hábiles (excluir fines de semana)
- ✅ Excluir holidays con fuente externa
- ✅ Patrones de "siguiente día hábil", "X días hábiles después"
- ✅ Manejar calendarios fiscales distintos (calendar vs fiscal year)
Patrón 1: ¿Es hoy día hábil?
Básico — sin holidays:
{{
(() => {
const dt = DateTime.now().setZone('America/Mexico_City');
return dt.weekday >= 1 && dt.weekday <= 5;
})()
}}
weekday en Luxon: 1 = lunes, 7 = domingo. 1-5 son días hábiles.
Patrón 2: Excluir holidays
Necesitas una fuente de holidays. Opciones:
Opción A: Sheet manual con holidays
Crear Sheet holidays_mx con columna date (yyyy-MM-dd):
2026-01-01
2026-02-05
2026-03-16
...
En el workflow:
[Sheets: leer holidays]
│
[Aggregate: into 'holidays_array']
│
[IF: es hoy un holiday]
{{ $json.holidays_array.map(h => h.date).includes(DateTime.now().toFormat('yyyy-MM-dd')) }}
Ventaja: simple, control total. Desventaja: mantener actualizado el Sheet anualmente.
Opción B: API pública de holidays
Hay APIs gratuitas:
- date.nager.at — holidays públicos por país
- calendarific.com — más completo, free tier limited
[HTTP GET https://date.nager.at/api/v3/PublicHolidays/2026/MX]
│
[Lista de holidays con fechas]
Ventaja: sin maintenance manual. Desventaja: dependencia externa.
Opción C: Combinar — Sheet + API
API para holidays nacionales + Sheet para holidays específicos de tu empresa (días de team building, etc.).
Patrón 3: "Siguiente día hábil"
Dada una fecha (posiblemente weekend/holiday), devolver el próximo día hábil:
{{
(() => {
let dt = DateTime.fromISO($json.date);
const holidays = $json.holidays; // array de strings 'yyyy-MM-dd'
while (true) {
const isWeekend = dt.weekday > 5;
const isHoliday = holidays.includes(dt.toFormat('yyyy-MM-dd'));
if (!isWeekend && !isHoliday) return dt.toISO();
dt = dt.plus({ days: 1 });
}
})()
}}
Avanza día por día hasta encontrar uno hábil.
Patrón 4: "X días hábiles después"
Dada fecha X y N días hábiles, calcular la fecha resultante:
{{
(() => {
let dt = DateTime.fromISO($json.date);
let count = 0;
const N = 5; // ej. 5 días hábiles
const holidays = $json.holidays;
while (count < N) {
dt = dt.plus({ days: 1 });
const isWeekend = dt.weekday > 5;
const isHoliday = holidays.includes(dt.toFormat('yyyy-MM-dd'));
if (!isWeekend && !isHoliday) count++;
}
return dt.toISO();
})()
}}
Loop hasta acumular N días hábiles.
Calendar Year vs Fiscal Year
Calendar Year
Enero 1 → diciembre 31. La mayoría de usos.
Fiscal Year
Empieza en otro mes. Common:
- US Federal: octubre 1 → septiembre 30 (siguiente año)
- UK: abril 6 → abril 5
- Japón: abril 1 → marzo 31
- México: generalmente calendar year
Calcular FY actual
{{
(() => {
const dt = DateTime.now();
// Ejemplo: FY empieza en abril
if (dt.month >= 4) {
return `FY${dt.year}-${dt.year + 1}`;
} else {
return `FY${dt.year - 1}-${dt.year}`;
}
})()
}}
Trimestres fiscales
Calendar quarters:
- Q1: ene-mar
- Q2: abr-jun
- Q3: jul-sep
- Q4: oct-dic
{{
(() => {
const month = DateTime.now().month;
return Math.ceil(month / 3); // 1-4
})()
}}
Para FY que no empieza en enero, ajustar la fórmula.
Cierre de mes contable
"Último día hábil del mes":
{{
(() => {
let dt = DateTime.now().endOf('month'); // último día calendar
const holidays = $json.holidays;
while (true) {
const isWeekend = dt.weekday > 5;
const isHoliday = holidays.includes(dt.toFormat('yyyy-MM-dd'));
if (!isWeekend && !isHoliday) return dt.toISO();
dt = dt.minus({ days: 1 });
}
})()
}}
Retrocede desde el último día calendar hasta encontrar uno hábil.
Caso completo: workflow "X días después del cierre"
Caso: Reporte que se envía 3 días hábiles después del cierre de mes.
[Schedule diario 9am]
│
[Set: calcular cierre del mes pasado]
│
[Set: calcular fecha objetivo = cierre + 3 días hábiles]
│
[IF: hoy === fecha objetivo]
├─ TRUE → [generar reporte]
└─ FALSE → fin
Cada día verifica si es el día objetivo. Si sí, ejecuta. Es la forma de scheduling complejo cuando cron no alcanza.
Trampas comunes
Trampa 1: No actualizar holidays anualmente
Qué pasa: Sheet de holidays tiene 2025. Llega 2026, workflow se confunde porque no encuentra los nuevos.
Cómo evitar:
- Pre-cargar 2-3 años adelante
- O usar API que siempre está actualizada
- Schedule anual que recuerde actualizar el Sheet manualmente
Trampa 2: Holidays distintos por región
Qué pasa: Workflow para LATAM. Usas holidays de México. Equipo en Argentina opera diferente.
Cómo evitar:
- Por país: holidays separados
- Por región dentro del país: estados/provincias con sus propios feriados
Trampa 3: Confundir "día hábil" con "business hours"
Qué pasa: Tu lógica detecta si es día hábil pero ejecuta a las 3am sábado. Día hábil sería el lunes, pero la hora también importa.
Cómo evitar: Combinar día hábil y business hours en la check.
Trampa 4: Empezar a contar desde el día actual o el siguiente
Qué pasa: "5 días hábiles desde hoy" — ¿incluye hoy o no?
Cómo evitar: Definir explícitamente en tu lógica. Usualmente "días después" excluye el día actual.
Resumen
- Cron no maneja business days — usar lógica en workflow
- Holidays: Sheet manual, API pública, o combinación
- Patrones: ¿hoy hábil?, siguiente hábil, +N hábiles, último hábil del mes
- Calendar vs Fiscal Year: ajustar fórmulas según empresa
- 4 trampas: holidays desactualizados, regional, business hours, conteo inclusive/exclusive
Lo que sigue: Scheduling dependiente — workflows que se disparan en cadena.
Creado: Mayo 11, 2026 Versión: 1.0