Skip to content

Instantly share code, notes, and snippets.

@IagoLast
Last active February 11, 2025 10:06
Show Gist options
  • Save IagoLast/0412a8d3901a615d6cdfaa094348abec to your computer and use it in GitHub Desktop.
Save IagoLast/0412a8d3901a615d6cdfaa094348abec to your computer and use it in GitHub Desktop.
TimeTime Challenge

Editor de horarios.

Introducción

En miles de aplicaciones web tenemos editores de horarios, visualmente son algo como esto:

https://cdn.dribbble.com/userupload/4020804/file/original-1fb78005e50233e423b22873f0c74f4a.png?resize=2048x1536&vertical=center

En TimeTime tenemos esto modelado de la siguiente forma:

const schedule: {
  timezone: 'Europe/Madrid',
  
  workingHours: {
    mon: [{ start: '09:00', end: '13:00' }, { start: '15:00', end: '18:00' }],
    tue: [{ start: '09:00', end: '13:00' }, { start: '15:00', end: '18:00' }],
    wed: [{ start: '09:00', end: '13:00' }, { start: '15:00', end: '18:00' }],
    thu: [{ start: '09:00', end: '13:00' }, { start: '15:00', end: '18:00' }],
    fri: [{ start: '09:00', end: '13:00' }, { start: '15:00', end: '17:00' }],
    sat: [{ start: '10:00', end: '14:00' }],
    sun: [], // Domingo libre
  }
}

Sin embargo este formato tiene una serie de problemas. La más evidente es que es complicado modelar horarios que no cierran a medianoche. Por ejemplo un bar que abra de 10:30 a 03:00.

Problema & pistas

La pregunta es muy sencilla, (la solución quizá no)

¿Qué formato se te ocurre para modelar horarios?

👉 Ten en cuenta los diferentes escenarios que se puedan dar.

👉 Los autores de las mejores respuestas recibirán entradas para la http://jsconf.es/ por cortesía de TimeTime.

👉 Puedes participar contestando a este gist, o por twitter, citando a @iagolast o a @odin_delrio

👉 No intentes copiar de nuestra API. Está mal y tenemos que actualizarla :trollface:

@javimostoles
Copy link

javimostoles commented Feb 10, 2025

Formato Propuesto

const schedule = {
  timezone: 'Europe/Madrid',
  workingHours: [
    { days: ['mon', 'tue', 'wed', 'thu'], start: '09:00', end: '13:00' },
    { days: ['mon', 'tue', 'wed', 'thu'], start: '15:00', end: '18:00' },
    { days: ['fri'], start: '09:00', end: '13:00' },
    { days: ['fri'], start: '15:00', end: '17:00' },
    { days: ['sat'], start: '10:00', end: '14:00' },
    { days: ['sun'], start: null, end: null }, // Cerrado

    // Un bar con horario que cruza la medianoche
    { days: ['fri', 'sat'], start: '18:00', end: '03:00' },
  ]
};

Soporte para intervalos cruzando medianoche

Cuando start > end, significa que el turno termina al día siguiente.
Por ejemplo, si start: "18:00" y end: "03:00", el horario realmente es:

•	Día original: 18:00 - 23:59
•	Día siguiente: 00:00 - 03:00

@coluccini
Copy link

Tal vez sería más simple no guardar un horario de cierre, sino la cantidad de horas que estará abierto desde la apertura.

const schedule: {
  timezone: 'Europe/Madrid',
  
  workingHours: {
    mon: [{ start: '09:00', hours_open: 4 }, { start: '15:00', hours_open: 4}], // de 9 a 13 y de 15 a 19
    tue:  [{ start: '09:00', hours_open: 4 }, { start: '15:00', hours_open: 4}],
    wed: [{ start: '09:00', hours_open: 4 }, { start: '15:00', hours_open: 4}],
    thu:  [{ start: '09:00', hours_open: 4 }, { start: '15:00', hours_open: 4}],
    fri:  [{ start: '09:00', hours_open: 4 }, { start: '15:00', hours_open: 4}],
    sat: [{ start: '22:00', hours_open: 4}], // abierto hasta el domingo a las 2 de la mañana
    sun: [], // Domingo libre
  }
}

@urielsalis
Copy link

Hay un standard para esto, ISO 8601 :D

https://en.wikipedia.org/wiki/ISO_8601#Time_intervals, que se puede simplificar/modificar (aunque la mayoria de los lenguajes ya lo hace) para incluir week day.
De paso se puede usar para definir holidays o tiempos del año que tienen diferentes horarios, usando un sistema de prioridad (mientras mas arriba mas prioridad)

Si usamos N como week day(donde domingo es 0, sabado es 6)

const schedule = {
  timezone: 'Europe/Madrid',
  workingHours: [
    { duration: "PM8/PM9", open: false}, -- Todo agosto cerrado
    { duration: "PN1TH9/PN1TH13", open: true}, -- Lunes abierto de 9 a 13
    { duration: "PN1TH15/PN1TH18", open: true}, -- Y tambien de 15 a 18, repetir para cada dia de la semana
    { duration: "PN5TH18/PN6TH3", open: true}, -- Viernes abierto de 18 a 3am del dia siguiente
  ]
};

@urielsalis
Copy link

urielsalis commented Feb 11, 2025

Si seguimos con el mantra de no reinventar la rueda, openstreetmap tambien tiene su propia especificacion https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification

La version que mejor funciona es la version en JS, podes comunicar la lista de reglas al FE sin problema

@torresgol10
Copy link

Para modelar horarios, yo usaría timestamps (o ISO 8601) para definir el primer evento (start/end) y un campo de recurrencia al estilo Google Calendar: reglas RRULE/RDATE/EXDATE (RFC 5545) que permitan manejar casos complejos: Ej: RRULE:FREQ=WEEKLY;COUNT=5;BYDAY=TU,FR

https://developers.google.com/calendar/api/concepts/events-calendars?hl=es-419#recurrence_rule

@GalindoSVQ
Copy link

GalindoSVQ commented Feb 11, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment