【问题标题】:Data structure for storing recurring events?用于存储重复事件的数据结构?
【发布时间】:2010-12-05 14:29:26
【问题描述】:

我正在寻找一种用于存储重复事件的数据结构模式,但我想出的一切都会导致大量特殊情况处理或用户输入和数据检索过于复杂。 (我有一种明显的感觉,我对问题领域的理解还不够好,无法做到这一点。)

如何存储 Outlook 样式的重复事件?

  • 每天早上 8 点
  • 每月的第一个星期二
  • 三年内每年 12 月 1 日
  • 每周每两小时一次
  • ...

【问题讨论】:

    标签: language-agnostic design-patterns data-structures


    【解决方案1】:

    有各种论文描述了这个用例的数据结构和算法。此外,您还可以查看crontabQuartz (Java) 或Quartz.NET (.NET) 的开源实现代码或说明。

    这是一篇这样的论文

    http://portal.acm.org/citation.cfm?id=359763.359801&coll=ACM&dl=ACM&CFID=63647367&CFTOKEN=55814330

    例如,cron 存储这样的信息(* 表示每个月,因此月份下的* 表示每个月)

    .---------------- 分钟 (0 - 59) | .------------- 小时 (0 - 23) | | .--------- 月中的某天 (1 - 31) | | | .------- 月 (1 - 12) 或 1 月、2 月、3 月、4 月 ... | | | | .---- 星期几 (0 - 6) (Sunday=0 or 7) OR 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 * * * *

    【讨论】:

      【解决方案2】:

      这是我的看法——如果我遗漏了什么,请告诉我:

      根据 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个整数和1个字符串。

      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 Appointment Recurrence scheduler 中出现的顺序输入 3 个整数,这样可以节省额外的字段、逻辑和烦恼。 *如果您打开 Outlook 应用程序调度程序,这将更容易理解:

      The RecurrenceType field can be any of the 7 following choices 
      

      (每天、每月和每年有 2 个选项,每周有一个选项):

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

      我希望我已经足够彻底地解释了这一点。如果有任何不清楚或不起作用,请告诉我。我正在为当前的应用程序构建它。谢谢大家。

      【讨论】:

      • 嘿!很好的答案!它给我留下了一个悬而未决的问题:是否有一种快速的方法来计算开始日期和结束日期之间的所有日期,而不需要迭代每个日期?
      【解决方案3】:

      支持标准的iCalendar事件类型

      IETF 在创建Internet 日历和调度核心对象规范(也就是众所周知的iCalendar)时考虑到了这一点。 p>

      规范包括事件重复。

      作为额外的奖励,您的数据库将能够与其他 iCalendar 兼容的数据源(例如 Google 和 Apple 日历)共享数据。

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

      【讨论】:

        【解决方案4】:
        事件: 开始日期 EndDate(根据 NumberOfOccurances 的变化计算) NumberOfOccurances(根据 EndDate 的变化计算) 频率1/2 小时、1 次/月、1 次/天、.... CorrectionFunction 例如第一个周二,上周日,... bool OccuresOn(day) 日期 NextOccurance(日期)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-01-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多