在构建日历应用程序时,我应该在数据库中存储日期或重复规则吗?

时间:2010-11-21 19:32:49

标签: c# calendar icalendar recurrence

我正在构建一个日历网站(ASP.NET MVC)应用程序(想想Outlook的简单版本),我想开始支持重复发生的日历事件(每月,每年等)

现在我正在存储我的实际日期,但我想弄清楚是否重复,是否继续存储日期(有一些明显的截止)是有意义的,或者我应该存储重复选项并生成日期在飞行中。

它让我思考Outlook,google mail等是如何做这个或任何其他支持重复日历项目的服​​务。

对此有什么建议吗?

7 个答案:

答案 0 :(得分:46)

将您的数据分为两部分:“规范”数据(重复规则)和“服务”(生成日期;除了重新生成之外的只读数据)。如果规范数据发生更改,请在该点重新生成“服务”数据。对于无限次重复,请保留一定数量的实例,并在用完时生成更多实例(例如,如果用户查看其2020年的日历)。

如果你有无限的处理器速度,你只需要规范数据 - 但实际上,对每个页面视图上的所有重复规则进行所有日期/时间处理可能是过于耗时...所以你需要权衡一些存储(和复杂性)以节省重复计算。与大量事件所需的计算相比,存储通常非常便宜。如果需要存储事件的日期,那真的非常便宜 - 您可以轻松地使用4字节整数来表示日期,然后从中生成完整的日期/时间,假设您的复发都是基于日期的。对于基于时间的重复(例如“每三个小时”),您可以使用完整的UTC时刻 - 只要您可能需要,8个字节就可以表示非常精细的分辨率。

您需要注意保持有效性 - 如果定期会议今天更改 ,那么 过去发生时不会发生变化...所以您可能希望具有关于实际发生重复的规范只读数据。显然你不会希望永远保持过去,所以你可能希望“垃圾收集”事件超过几年,具体取决于你的存储限制。

您可能还需要能够在每次出现的基础上添加注释和例外(例如,“因公共假日而未在今天开会”或“移至下午4点”)。当您更改重复时,这变得非常有趣 - 如果您将“每个星期一”更改为“每个星期二”,您是否保留了例外情况?当你从“每一天”变为“每周”时,你如何匹配例外情况?这些不是直接关于存储的问题 - 但存储决策将影响实施您决定的任何政策的容易程度。

答案 1 :(得分:7)

我必须建立一个与调度一起工作的系统,我们做了两个。这就是我们所拥有的

  • 一组跟踪时间表的表格。
  • 跟踪计划的先前实例(实际发生时间)的表格
  • 跟踪上一个和下一个实例的表(当下一个项目将根据上次发生时)你不需要这个表,但是我们使用它,因为否则你会不断地计算现在应该发生一件事

通过安排,事情可能变得非常棘手,因为您必须记住,在任何时间点,时间表都可能发生变化。此外,当您的应用程序未运行时,项目可能到期,当它再次启动时,您需要知道如何识别过期项目。

此外,我们确保跟踪实际时间表的表格是独立的。原因是这些是系统中最复杂的表集合,我们希望能够重用它们,以便它们可以用于需要调度的不同事物。例如发送管理员电子邮件,发送通知以及清理日志文件等服务器维护。

答案 2 :(得分:7)

您需要单独处理事件和事件。

活动明智: 对于事件,您将需要存储recurence规则(可以是rfc5545指定的rrule,但也可以是rfc5545中的rdate等明确的日期集),但也有异常(请参阅rfc5545的exdate以及rfc2445中可能的exrule)。 您还需要跟踪这些规则的变化: rdate,exdate的变化在将来发生时没有问题,在过去的日期会被忽略。 由于影响之前的出现,rrule的变化更加棘手。我个人的偏好是为新旧套期添加一个特定属性,以指定其各自的开始和结束日期。

如果事件的时间跨度有限(比如说COUNT或UNTIL属性),则应将其开始和结束存储在表中,以便更容易查询事件(特别是在预先计算的时间窗口之外查找事件时(见下文) ),它可以帮助减少重新计算的事件数量。)

发生的事情: 对于出现的情况,您应该将实例存储在当前周围的预定义窗口内(例如+/- 6个月或12个月并定期计算)并保留此记录以允许重新计算,如果您的用户希望将来进一步查看(对于表演问题)。您还应该考虑计算索引(RECURRENCE-ID)以帮助更容易地找到下一个匹配项。

在后端更少,但在前端更多,您还应该跟踪tzid更改,以询问用户是否在某个给定tzid上安排的事件是否意味着保留在当前时区需要更新(想想萨摩亚岛上有人安排在2011年12月30日星期五举行会议,然后国家决定这一天不存在),同样地,你可以询问在夏令时期间发生的事件是否意味着“永远不会发生”或“发生两次”(更多关于这个话题here

注意: 你可能想要考虑rfc5545中定义的支持,而不仅仅是恢复规则,还要添加对宗教经常性规则(see USNO introduction to calendars或印刷“日历计算”(第三版)的支持。 E. Reingol和N. Dershowitz)。

由于您询问现有实现,您可以轻松检查sunbird(sqlite)或Apple open source Calendar and Contacts Server的数据库模式,这是caldav服务器的现有开源项目的更完整列表(可能是您正在寻找的是什么)here

答案 3 :(得分:3)

我肯定会使用你的第二个选项。使用不同的重复选项,单独存储并动态计算。存储所有这些日期将是一大堆不必要的数据。

这是一个很好的答案来赞美你的问题 Data structure for storing recurring events?

另外,作为旁注。我已经开始将所有内容存储为UTC时间,以便在需要使用多个时区时有一个共同的基线。

答案 4 :(得分:1)

您需要确保存储其中一些。用户可能会编辑其中一个事件,而其他事件保持不变(您可能会遇到一个问题:“您想编辑所有定期事件,还是仅编辑此事件?”在某些日历中,即Windows Mobile)。

您还可能希望存储过去的事件,而不是在用户删除定期事件时将其删除。

如果您存储所有其他人或生成它们是一个实现细节。如果可能的话,我更愿意生成它们。

在任何情况下,您都希望在每个事件中都存储一些周期性事件的ID,另外还有一些标志告诉您事件是否稍后被修改。或者在更复杂的方法中,每个事件属性的标志告诉,如果它是默认值(来自重复事件)或者是否为此特定实例修改了它。当用户决定编辑定期事件时,您将需要此功能。

答案 5 :(得分:0)

我在几年前制作的网络应用程序中遇到了类似的问题(现在可能有更好的方法:))。我想要包含一个调度程序,它具有周期性事件,处理时间,日期,周,月,年和异常的所有功能,因此我可以使用以下规则:

1)每天上午10点(星期三除外)

2)每2小时一次,每天最多4次迭代

3)每个月的第一个星期一

等。

存储重复的日期/时间是可能的,但不灵活。当"最大值"时,事件的每次迭代都会发生变化。将会。你看多远了?

最后,我写了一个自定义调度类,可以读取和写入字符串。这是存储在数据库中的字符串,然后可以调用一个简单的函数来查找下一次出现的时间。

答案 6 :(得分:0)

请注意,大多数答复都倾向于保存生成的数据。但是请确保您考虑了用例。

过去,我的服务器受到io的限制,许多cpu无所作为。如今,您已经有了固态硬盘(如果您负担得起的话),但请注意,左侧带有老式的高清硬盘,但请注意,核心数量也已增加。

关于这种计算的好处是,您可以轻松地将它们拆分,然后将它们分配给您的许多核心,甚至分配给本地网络中的一些廉价服务器。通常比设置nosql集群或采用完整的数据库集群方式便宜。

还有一种可能是缓存,只需缓存您的日历视图,无需在没有任何更改的情况下每次都进行所有计算。

但是正如所说的,这取决于您的用例。不要只是按照上面的答案,而是要自己做些计算,然后再做决定。