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:

[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