存储重复事件的数据结构?

35

我正在寻找一种数据结构模式来存储重复事件,但我想到的所有方法都会导致需要处理大量特殊情况,或者用户输入和数据检索过于复杂。(我感到强烈的感觉是我对问题领域的理解还不够。)

如何存储类似于Outlook的重复事件?

  • 每天早上8点
  • 每个月的第一个星期二
  • 每年12月1日连续三年
  • 每两小时连续一周
  • ...
4个回答

18

支持标准的 iCalendar 事件类型

当创建互联网日历和调度核心对象规范(Internet Calendaring and Scheduling Core Object Specification),更为人所知的是iCalendar时,IETF考虑了一些因素。

该规范包括事件重复发生。

另外,您的数据库将能够与其他iCalendar兼容的数据源共享数据,例如Google和Apple日历等。

https://www.rfc-editor.org/rfc/rfc5545


18
有各种文献描述了这种用例的数据结构和算法。此外,您可以查看开放源代码实现crontabQuartz(Java)或Quartz.NET(.NET)的代码或描述。
以下是其中一篇论文: http://portal.acm.org/citation.cfm?id=359763.359801&coll=ACM&dl=ACM&CFID=63647367&CFTOKEN=55814330 例如,crontab将信息存储如下(*表示每个,因此在月份下面的一个*表示每月):
.---------------- 分钟 (0 - 59) 
|  .------------- 小时 (0 - 23)
|  |  .---------- 日 (1 - 31)
|  |  |  .------- 月份 (1 - 12) 或 jan,feb,mar,apr ... 
|  |  |  |  .---- 星期几 (0 - 6) (星期天=0或7) 或 sun,mon,tue,wed,thu,fri,sat 
|  |  |  |  |
*  *  *  *  *
有几个特殊条目,其中大多数只是快捷方式,可以使用它们来代替指定完整的cron条目:
条目 描述 等价于 @reboot 开机时运行一次。 无 @yearly 每年运行一次 0 0 1 1 * @annually (与@yearly相同) 0 0 1 1 * @monthly 每月运行一次 0 0 1 * *@weekly 一周运行一次 0 0 * * 0 @daily 一天运行一次 0 0 * * * @midnight (同@daily) 0 0 * * * @hourly 一小时运行一次 0 * * * *

6
事件:
开始日期 结束日期(根据发生次数的更改进行计算) 发生次数(根据结束日期的更改进行计算) 频率,例如每2小时、每月1次、每天1次等等。 修正函数,例如第一个星期二、最后一个星期日等等。
bool 在某一天发生(day) Date 下一个事件(date)

5

以下是我的想法,请告知我有没有遗漏什么:

根据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)

我按照在Outlook预约重复安排程序中出现的顺序输入这3个整数,这样可以节省额外的字段、逻辑和烦恼。 *如果您打开Outlook预约安排程序,这将稍微容易一些:

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...

我希望我的解释足够详细。如果有任何不清楚的地方或者不能工作,请告诉我。我正在为一个现有的应用程序构建这个。感谢所有人。


2
嘿!非常好的答案!这让我有一个问题:是否有一种快速计算开始日期和结束日期之间所有日期的方法,而不必迭代每个日期? - Lars Petersen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接