Saltar al contenido principal

Intervalos de tiempo

Un atributo timeInterval es una regla de recurrencia, no una lista de franjas: una fecha de anclaje, rangos horarios diarios e indicadores de repetición. Para convertirlo en pares [start, end] concretos para la ventana que muestras, usa las utilidades de nivel superior expandAttributeTimeIntervals y expandTimeIntervals y la guarda de tipo isTimeIntervalAttribute.

import { expandAttributeTimeIntervals } from 'oneentry';

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});
// [['2025-04-14T09:00:00.000Z', '2025-04-14T10:00:00.000Z'], …]

Las tres utilidades son puras: no modifican su entrada ni hacen solicitudes.

Dónde están los horarios​

La API devuelve los horarios con dos formas, y las utilidades aceptan ambas:

FormaDónde encontrarlaContiene
Entidad (ITimeIntervalEntitySchedule)attributeValues[marker].value[].values[] en páginas, productos, bloques y conjuntos de atributosun rango dates con pares times
Formulario (ITimeIntervalSchedule)attributes[].localizeInfos.intervals[] en los formulariosun range con intervals que llevan un period de franja en minutos

expandAttributeTimeIntervals(attr, window)​

Despliega un atributo de entidad en una sola llamada: recorre los grupos y horarios del atributo, despliega cada uno y combina los resultados. La combinación es importante, porque la eliminación de duplicados y el orden solo se garantizan dentro de un único horario; si combinas los grupos a mano, puedes obtener franjas duplicadas o desordenadas.

Para cualquier cosa que no sea un atributo timeInterval devuelve un array vacío, así que puedes llamarla sin comprobar antes type.

import { expandAttributeTimeIntervals } from 'oneentry';

const page = await Pages.getPageByUrl('booking');
if ('statusCode' in page) throw new Error(page.message);

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});

expandTimeIntervals(schedule, window)​

Despliega un único horario. Úsala cuando ya tienes uno, normalmente en los formularios, cuyos horarios ya están tipados en localizeInfos.intervals:

import { expandTimeIntervals } from 'oneentry';

const form = await Forms.getFormByMarker('booking_form');
if ('statusCode' in form) throw new Error(form.message);
const field = form.attributes.find((a) => a.marker === 'schedule');

const slots = (field?.localizeInfos.intervals ?? []).flatMap((schedule) =>
expandTimeIntervals(schedule, { from: '2025-05-01', to: '2025-05-31' }),
);

isTimeIntervalAttribute(attr)​

IAttributeValue.value tiene el tipo unknown, porque su forma depende de type. Esta guarda de tipo acota un atributo a ITimeIntervalAttributeValue, para que puedas acceder a los horarios sin una conversión de tipo:

import { isTimeIntervalAttribute } from 'oneentry';

const attr = page.attributeValues.interval;

if (isTimeIntervalAttribute(attr)) {
attr.value[0].values[0].dates; // fully typed
}

La ventana​

const window = { from: '2025-04-01', to: '2025-04-30' };
  • from y to aceptan un Date, una cadena ISO o milisegundos desde epoch.
  • Ambos límites son inclusivos y se comparan por día UTC; la hora del día en from/to se ignora.
  • La ventana es obligatoria: un horario es una regla de recurrencia abierta, y solo tú sabes hasta dónde desplegarla.

Semántica de la recurrencia​

  • dates[0] / range[0] es a la vez la fase de la recurrencia y el primer día válido. No se devuelve nada anterior, por amplia que sea la ventana.
  • dates[1] / range[1] termina la validez. Si no es posterior al inicio, el horario se ancla a ese único día; con un indicador de recurrencia activado, la recurrencia pasa a ser abierta y solo la ventana limita el resultado.
  • inEveryWeek se repite cada 7 días a partir del anclaje.
  • inEveryMonth se repite el mismo día del mes y omite los meses que son demasiado cortos.
  • Con ambas opciones activadas, se aplica la regla semanal.
  • Sin ningún indicador, el horario es un simple rango de fechas: cada día del rango produce franjas.
  • El resultado no tiene duplicados y está ordenado por inicio y luego por fin.
  • Todos los cálculos se hacen en UTC, así que el resultado no depende de la zona horaria de la máquina.

Migrar desde el campo timeIntervals​

Las versiones anteriores del SDK añadían un array timeIntervals calculado a cada valor de atributo timeInterval. Ese campo ya no existe. Contenía un año completo de franjas independientemente de lo que necesitara quien hacía la llamada: un solo atributo con franjas de una hora se desplegaba en unas 2000 líneas de JSON, y con periodos de franja más finos se llegaba a megabytes, suficiente para superar los límites de la caché de datos de los frameworks. Además, nunca se declaró en ninguna interfaz ni esquema, así que el código TypeScript solo podía acceder a él mediante una conversión de tipo.

Antes, se leía el campo precalculado:

const slots = page.attributeValues.interval.value[0].values[0].timeIntervals;

Ahora, expande la ventana que realmente renderizas:

import { expandAttributeTimeIntervals } from 'oneentry';

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});

Los datos de origen (dates/range, times/intervals, inEveryWeek, inEveryMonth) no cambian y siguen presentes en cada horario. No se pierde nada: las franjas se calculan bajo demanda en lugar de por adelantado, y lo que se almacena en caché es la regla compacta.

Los métodos _addTimeIntervalsToSchedules y _addTimeIntervalsToFormSchedules también se eliminaron de todos los módulos (a pesar del prefijo _, se podían llamar, p. ej., Pages._addTimeIntervalsToSchedules). Usa expandTimeIntervals en su lugar.

Tipos​

Todos ellos se exportan desde la raíz del paquete y desde oneentry/types (consulta Importar tipos):

TipoDescribe
ITimeIntervalAttributeValueUn IAttributeValue acotado a type: 'timeInterval', cuyo value es un array de grupos
ITimeIntervalGroupUna entrada del value del atributo: horarios que comparten un intervalId
ITimeIntervalEntityScheduleUn horario de entidad: dates, times, inEveryWeek, inEveryMonth
ITimeIntervalScheduleUn horario de formulario: range, intervals, inEveryWeek, inEveryMonth
ITimeIntervalRangeUn rango diario con start, end y un period de franja en minutos (null cuando no está dividido)
ITimeIntervalPointUn momento del día: { hours, minutes }
ITimeIntervalWindowLa ventana de despliegue: { from, to }
TimeIntervalPairUna franja resuelta: [start, end], ambas cadenas ISO 8601 en UTC

Ejemplo: mostrar un mes de franjas​

import { expandAttributeTimeIntervals } from 'oneentry';

const page = await Pages.getPageByUrl('booking');

if ('statusCode' in page) {
throw new Error(page.message);
}

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});

// Group the slots by day for a calendar view
const byDay = slots.reduce((acc, [start, end]) => {
const day = start.slice(0, 10);
(acc[day] ??= []).push([start, end]);
return acc;
}, {} as Record<string, Array<[string, string]>>);

Relacionado​