Структура данных для хранения повторяющихся событий?
Я ищу шаблон структуры данных для хранения повторяющихся событий, но все, что я придумал, приведет к большому количеству обработки особых случаев или ввода пользователя и поиска данных. (Я получаю отчетливое чувство, что я недостаточно понимаю проблему, чтобы сделать это.)
Как сохранить повторяющиеся события в стиле Outlook?
- Каждый день в 8 утра
- Каждый первый вторник в месяц
- Каждый 1 декабря в течение трех лет
- Каждые два часа в неделю
- ...
Ответы
Ответ 1
Существуют различные документы, описывающие структуры данных и алгоритмы для этого варианта использования. Кроме того, вы можете увидеть код или описания реализации с открытым исходным кодом crontab и Quartz (Java) или Quartz.NET (.NET).
Это одна из таких статей
http://portal.acm.org/citation.cfm?id=359763.359801&coll=ACM&dl=ACM&CFID=63647367&CFTOKEN=55814330
Например, cron хранит такую информацию (*
означает каждый, поэтому месяц *
означает месяц)
.---------------- 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 * * * *
Ответ 2
Поддержка стандартных типов событий iCalendar
IETF задумался над этим, когда они создали спецификацию базового объекта Интернета для календаря и планирования, более известную как iCalendar.
Спецификация включает повторение событий.
В качестве дополнительного бонуса ваша база данных будет поддаваться обмену данными с другими источниками данных, совместимыми с iCalendar, такими как календари Google и Apple.
http://tools.ietf.org/html/rfc5545
Ответ 3
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)
Ответ 4
Вот мой прием - пожалуйста, дайте мне знать, если мне что-то не хватает:
На основе параметров повторения Outlook у вас есть таблица с регулярными необходимыми полями:
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
Здесь происходит волшебство. для этой логики требуется только 4 целых числа и одна строка.
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)
Я ввожу 3 целых числа в том порядке, в котором они появляются в планировщике Outlook Recurrence, это экономит дополнительные feilds, логику, раздражение.
* Если вы откроете планировщик перспективы, это будет немного проще:
The RecurrenceType field can be any of the 7 following choices
(Существует два варианта ежедневного, ежемесячного и годового и один вариант для еженедельного):
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
Код для вытягивания или сохранения повторного появления становится довольно простым.
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...
Надеюсь, я достаточно подробно объясню это. Дайте мне знать, если что-то неясно или это не сработает. Я создаю это для текущего приложения. Спасибо всем.