language agnostic - Estructura de datos para almacenar eventos recurrentes?
language-agnostic design-patterns (4)
Estoy buscando un patrón de estructura de datos para almacenar eventos recurrentes, pero todo lo que surgió resultaría en un alto número de manejo de casos especiales o la entrada del usuario y la recuperación de datos son demasiado complejos. (Tengo la clara sensación de que no he entendido el dominio del problema lo suficientemente bien como para hacer esto).
¿Cómo puedo almacenar eventos recurrentes al estilo de Outlook?
- Todos los días a las 8 a.m.
- Cada primer martes en un mes
- Cada 1 de diciembre por tres años
- Cada dos horas durante una semana
- ...
Aquí está mi opinión: por favor, avíseme si me falta algo:
En función de las opciones de recurrencia de Outlook, tiene una tabla con los campos regulares necesarios:
FieldName DataType Sample Data
ID int primary key
EventID int foreign key (to EventID from Event Table)
StartTime DateTime 8:00 AM
EndTime DateTime 8:30 AM
Duration int 30 (minutes)
StartDate DateTime 01/25/2014
EndBy DateTime 01/25/2024
NoEndDate bit False
NumOccurrences int 10
RecurrenceType int ****See below for instructions on how to use these last 6 fields
Int1 int
Int2 int
Int3 int
String1 nvarchar(50)
IntYears int
Aquí es donde sucede la magia. esta lógica solo requiere 4 enteros y una cadena.
The month of year (1 = Jan, 12 = Dec),
The day of the month (1 = the 1st, 31 = 31st),
Day of the week (0 = Sunday, 1=Monday, 6= Saturday),
Week of the month (1 = first, 4 = forth, 5 = last),
Yearly reocurrence ( 1=1,2=2)
When multiple days can be selected I use a comma delimited string (1,3,5 = Monday, Wed, Friday)
Ingreso los 3 enteros en el orden en que aparecen en el planificador de periodicidad de citas de perspectiva, esto ahorra campos adicionales, lógica, molestia. * Si abre el planificador de citas de Outlook, esto será un poco más fácil de seguir:
The RecurrenceType field can be any of the 7 following choices
(Hay 2 opciones para diario, mensual y anual, y una opción para semanalmente):
10 = Daily (Every `Int1` day(s) )
Every 4 day(s)
11 = Daily (Every Weekday) -- no variables needed
Every Weekday (MTWTF)
20 = Weekly (Recur every `Int1` week(s) on: `String1`
Recur every 3 week(s) on Monday, Wednesday, Friday
(`String1` will be a list of days selected (0=Sunday, 1=Monday, 2=Tuesday... 7=Saturday) so for (Mon, Wed, Fri) String1 would hold "1,3,5". You would parse this on the code side to pull the actual days.)
30 = Monthly (Day `Int1` of every `int2'' month(s)
Day 28 of every 2 month(s)
31 = Monthly (The `Int1` `Int2` of every `Int3` month(s)
The forth Tuesday of every 1 month(s)
40 = Yearly (Recur every `intYears` year(s) On `Int1` `Int2`) --
Recur every 1 year(s) on Jan 28th
41 = Yearly (Recur every `intYears` year(s) on the `Int1` `Int2` of `Int3`) --
Recur every 1 year(s) on the forth Tuesday of January
El código para extraer o guardar la repetición se vuelve bastante simple
if (RecurrenceType = 10 )
Every `int1` days
if (RecurrenceType = 11)
Every Weekday
if (RecurrenceType = 20)
Every `int1 weeks on
parse `string1` and populate checkboxes for Mon, Tues, ...
if (RecurrenceType = 30)
`int1 day of every `int2` month
etc...
Espero estar explicando esto lo suficiente. Avíseme si algo no está claro o si no funciona. Estoy construyendo esto para una aplicación actual. Gracias a todos.
Hay varios documentos que describen estructuras de datos y algoritmos para este caso de uso. Además, puede ver el código o las descripciones de la implementación de código abierto de crontab y de Quartz (Java) o Quartz.NET (.NET).
Este es uno de esos papeles
http://portal.acm.org/citation.cfm?id=359763.359801&coll=ACM&dl=ACM&CFID=63647367&CFTOKEN=55814330
Por ejemplo, cron almacena la información de esta manera ( *
significa cada, por lo que a *
debajo del mes significa todos los meses)
.---------------- minute (0 - 59) | .------------- hour (0 - 23) | | .---------- day of month (1 - 31) | | | .------- month (1 - 12) OR jan,feb,mar,apr ... | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat | | | | | * * * * * There are several special entries, most of which are just shortcuts, that can be used instead of specifying the full cron entry: Entry Description Equivalent To @reboot Run once, at startup. None @yearly Run once a year 0 0 1 1 * @annually (same as @yearly) 0 0 1 1 * @monthly Run once a month 0 0 1 * * @weekly Run once a week 0 0 * * 0 @daily Run once a day 0 0 * * * @midnight (same as @daily) 0 0 * * * @hourly Run once an hour 0 * * * *
Admite los tipos de eventos de iCalendar estándar
El IETF reflexionó sobre esto cuando crearon la especificación de calendarios y programación de objetos principales de Internet , mejor conocida como iCalendar .
La especificación incluye la repetición del evento.
Como una ventaja adicional, su base de datos podrá compartir datos con otras fuentes de datos compatibles con iCalendar, como los calendarios de Google y Apple.
Event: StartDate EndDate (calculated on change of NumberOfOccurances) NumberOfOccurances (calculated on change of EndDate ) Frequency e.g. 1/2hrs, 1/month, 1/day, .... CorrectionFunction e.g. first Tuesday, last Sunday, ... bool OccuresOn(day) Date NextOccurance(date)