Skip to content

Excepciones de eventos

Los eventos recurrentes se repiten por regla. La vida real no. Navidad cae en domingo y desplaza el servicio matutino regular a un horario nocturno; un día feriado cierra el edificio y cancelas la reunión de oración de un miércoles; un orador invitado significa un cambio de título de una semana. Las excepciones son cómo GCM maneja esas ediciones sin reescribir la RRULE subyacente.

Dos mecanismos, un propósito

GCM tiene dos formas de hacer que una sola fecha se comporte diferente al resto de una serie:

  1. events.exception_dates — una columna date[] en el evento mismo. Agrega una fecha aquí y esa ocurrencia desaparece del calendario. Sin join de tabla, sin fila extra.
  2. Tabla event_exceptions — una fila por anulación, con campos para cancelar, retitular, recalendarizar o reubicar una ocurrencia.

La primera es para el caso simple ("solo omitir esta fecha"). La segunda es para todo lo demás.

sql
event_exceptions(
  id, event_id, exception_date,
  is_cancelled, override_title,
  override_start_time, override_end_time,
  override_location, created_at
)

La exception_date es la fecha en la que el evento padre habría caído, antes de que la anulación entrara en efecto. Cada otro campo es opcional — cualquier cosa que dejes en null cae al valor del evento padre.

Cancelar una ocurrencia

El caso más común: un Servicio Dominical regular se suspende porque están pintando el edificio, o una reunión de oración semanal se omite por un día feriado.

Dos formas equivalentes de hacerlo:

  • Vía rápida — agrega la fecha a events.exception_dates. La ocurrencia desaparece de la cuadrícula del calendario.
  • Vía auditable — inserta una fila event_exceptions con is_cancelled = true. La ocurrencia también desaparece, pero ahora tienes un registro de por qué fue cancelada (visible a admins cuando abren la fecha).

Para omisiones ocasionales, la vía rápida es suficiente. Para cancelaciones que podrías necesitar explicar después (cazadores de reembolsos, disputas de asistencia), la vía auditable deja rastro.

Mover una ocurrencia

Cuando la ocurrencia sigue pasando pero a una hora o lugar diferente, usa la fila event_exceptions para anular solo los campos que cambian. El resto cae en cascada del evento padre:

sql
INSERT INTO event_exceptions (event_id, exception_date, is_cancelled,
                              override_start_time, override_location)
VALUES ('<id>', '2026-12-24', false,
        '19:00', 'Sanctuary — candlelight setup');

El 24 de diciembre el calendario aún muestra el evento, pero el chip de hora lee 7:00 PM y el lugar lee "Sanctuary — candlelight setup." La serie sigue repitiéndose en su ritmo normal del domingo en la mañana después.

Campos de anulación disponibles:

  • override_title — reemplaza el título para esa fecha única. "Servicio Dominical" se vuelve "Servicio de Nochebuena."
  • override_start_time / override_end_time — desplaza las horas. Usa ambos si la duración también cambia.
  • override_location — apunta a los asistentes a otro lugar por ese día.

Si necesitas anular campos que la tabla de excepciones no lleva — color, descripción, sede — la anulación no es lo suficientemente expresiva. Tendrás que bifurcar: elimina la ocurrencia con una excepción, luego crea un evento único separado para la fecha cambiada.

Excepciones vs actualizaciones de RRULE

Una pregunta frecuente: ¿debo editar la regla de recurrencia, o agregar una excepción? La regla general:

  • Una o dos fechas cambian → agrega excepciones. La regla sigue describiendo el patrón normal, y las excepciones describen las desviaciones.
  • El patrón mismo cambia hacia adelante → edita la RRULE. Nueva fecha de fin, nuevo día de la semana, nuevo modo mensual. La regla siempre debe describir lo que es normal, no lo que fue normal.
  • Pasar de semanal a quincenal a mitad de año → termina la regla actual con UNTIL=<switchover>, luego crea un nuevo evento con la nueva regla comenzando después de esa fecha. No intentes codificar la transición dentro de una sola RRULE — los cambios de INTERVAL a mitad de serie no son representables.

El movimiento equivocado es eliminar el evento recurrente cuando algo cambia, porque la eliminación remueve lógicamente cada ocurrencia incluyendo las pasadas atadas a asistencia y reportes. El movimiento correcto es casi siempre: agrega una excepción, o termina la serie actual e inicia una nueva.

Cómo se renderizan las excepciones

En las vistas de mes y próximos, la lógica de excepciones corre del lado del cliente como parte de la expansión de RRULE:

  1. El navegador le pregunta al evento padre "¿en qué fechas caerías en esta ventana?"
  2. Filtra cualquier fecha en events.exception_dates.
  3. Filtra cualquier fecha donde event_exceptions.is_cancelled = true.
  4. Para las fechas que sobreviven, superpone los campos de anulación de cualquier fila event_exceptions no cancelada encima de los valores por defecto del evento padre.

Eso significa que una excepción con is_cancelled = false más override_title = 'Christmas Eve Service' aparece en la cuadrícula con el nuevo título pero con la hora, lugar y color del padre — a menos que estos también sean anulados.

Cuándo pensar diferente

Si te encuentras agregando muchas excepciones a un evento, el patrón está mal. Un Servicio Dominical que se retitula seis veces al año para servicios especiales es señal de que deberías mantener "Servicio Dominical" aburrido y agregar eventos únicos separados para las fechas especiales — Nochebuena, Pascua, etc. Las excepciones son mejores como la corrección rara, no como el modo normal.

Para las reglas que gobiernan el patrón normal, ve Patrones recurrentes. Para fechas únicas que no están atadas a una serie recurrente en absoluto, simplemente crea un nuevo evento.