36

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

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

它让我想到了 Outlook、谷歌邮件等如何执行此操作或任何其他支持定期日历项目的服​​务。

对此有什么建议吗?

4

7 回答 7

58

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

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

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

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

于 2012-04-14T07:16:19.217 回答
14

您将需要分别处理事件和事件。

事件明智:对于事件,您需要存储重复规则(可以是 rfc5545 指定的规则,也可以是 rfc5545 中的 rdate 等明确的日期集),但也有例外(参见 rfc5545 的 exdate 和可能的 rfc2445 中的 exrule) . 您还需要跟踪这些规则中的更改: rdate、exdate 中的更改在将来发生时没有问题,并且对于过去的日期将被忽略。规则的变化更棘手,因为会影响以前的事件。我个人的偏好是为新旧规则添加一个特定的属性,以指定它们各自的有效期开始和结束日期。

如果事件的时间跨度有限(例如存在 COUNT 或 UNTIL 属性),则应将其开始和结束存储在表中,以便更轻松地查询事件(尤其是在查找超出预计算时间窗口的事件时(见下文),它可以帮助减少要重做计算的事件的数量)。

明智的发生:对于发生的情况,您应该将实例存储在当前的预定义窗口内(例如 +/- 6 个月或 12 个月并定期计算)并保留记录以允许重新计算,如果您的用户希望在未来(性能问题)。您还应该考虑计算索引 (RECURRENCE-ID) 以帮助更轻松地查找下一个事件。

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

注意:您可能需要考虑超出 rfc5545 中定义的重复规则的支持,并添加对宗教重复规则的支持(参见 USNO 对日历的介绍或 E. Reingol 和 N 的印刷品“日历计算”(第三版) . 德肖维茨)。

由于您询问现有实现,您可以轻松检查 sunbird (sqlite) 或Apple 开源日历和联系人服务器的数据库模式,这是 caldav 服务器现有开源项目的更完整列表(这可能是您正在寻找)可在此处获得)

于 2012-04-15T16:30:11.417 回答
10

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

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

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

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

于 2010-11-21T20:00:31.140 回答
3

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

这是一个很好的答案来恭维您的问题。
用于存储重复事件的数据结构?

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

于 2010-11-21T19:36:21.670 回答
1

我在几年前制作的 Web 应用程序中遇到了类似的问题(现在可能有更好的方法 :))。我想包含一个调度程序,它具有重复事件的所有功能,处理时间、天、周、月、年和异常,这样我就可以有如下规则:

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

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

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

ETC..

存储重复的日期/时间是可能的,但不灵活。当“最大值”出现时,您的事件的每次迭代都会发生变化。你看起来有多远?

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

于 2010-11-21T19:38:11.653 回答
1

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

您可能还希望存储过去的事件,而不是在用户删除重复事件时删除它们。

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

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

于 2012-04-15T12:49:13.017 回答
1

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

回到过去,我的服务器受到 io 的限制,很多 cpu 什么都不做。现在你有ssd(如果你买得起的话,否则你的左边有一个旧的旋转高清),但请注意核心数量也增加了。

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

替代方案也可能是缓存,只需缓存您的日历视图,无需每次都没有更改时进行所有计算。

但正如所说,这取决于您的用例。不要只遵循上述答案,如果您有时间并做出决定,请自行计算。

于 2018-07-02T18:56:10.203 回答