在日历应用程序中为重复事件建模的最佳方法是什么?

Cli*_*ach 213 ruby algorithm recurrence calendar data-modeling

我正在构建一个需要支持重复事件的组日历应用程序,但是我提出来处理这些事件的所有解决方案看起来都像是一个黑客.我可以限制前方可以看到的距离,然后立即生成所有事件.或者我可以将事件存储为重复,并在日历上向前看时动态显示它们,但如果有人想要更改特定事件实例的详细信息,我将不得不将它们转换为正常事件.

我确信有更好的方法可以做到这一点,但我还没有找到它.对重复事件建模的最佳方法是什么,您可以在其中更改特定事件实例的详细信息或删除特定事件实例?

(我正在使用Ruby,但请不要让这限制你的答案.如果有一个特定于Ruby的库或其他东西,那么,这很有用.)

小智 84

我将对所有未来的重复事件使用"链接"概念.它们动态显示在日历中并链接回单个参考对象.当事件发生时,链接被破坏,事件变为独立实例.如果您尝试编辑定期事件,则提示更改所有将来的项目(即更改单个链接引用)或仅更改该实例(在这种情况下将其转换为独立实例,然后进行更改).由于您需要跟踪转换为单个实例的所有未来事件的重复列表,因此后者的问题稍有问题.但是,这完全是可行的.

因此,实质上,有两类事件 - 单个实例和重复事件.


Dan*_*rić 54

Martin Fowler - Calendars的重复活动包含一些有趣的见解和模式.

Runt gem实现了这种模式.


ang*_*son 32

重复发生的事件可能会有很多问题,让我重点介绍一下我所知道的事件.

解决方案1 ​​ - 没有实例

存储原始约会+重复数据,不存储所有实例.

问题:

  • 您需要在需要时计算日期窗口中的所有实例,成本高昂
  • 无法处理异常(即,您删除其中一个实例,或移动它,或者更确切地说,您不能使用此解决方案执行此操作)

解决方案2 - 存储实例

存储1中的所有内容,但也存储所有实例,链接回原始约会.

问题:

  • 占用了大量空间(但空间很便宜,很小)
  • 必须优雅地处理异常,特别是如果您在发出异常后返回并编辑原始约会.例如,如果您向前移动第三个实例,如果您返回并编辑原始约会的时间,在原始日期重新插入另一个并离开移动的约会,该怎么办?取消移动的移动链接?尝试适当更改移动的?

当然,如果你不打算做例外,那么任何一个解决方案都应该没问题,你基本上可以选择时间/空间权衡方案.

  • 如果您的定期约会没有结束日期怎么办?像空间一样便宜,你没有无限的空间,所以解决方案2在那里是一个非首发...... (34认同)
  • 解决方案#1实际上可以处理异常.例如,RFC5545建议将它们存储为:a)排除日期列表(删除事件时); b)引用原型的"物化"事件(当你移动一个事件时). (13认同)
  • @User - 确认,谢谢。这太奇怪了 - 我在 4 年前发表评论,从那时起我真的不需要处理这个问题。就在昨天,我开始设计一个涉及重复约会的新模块,我想知道如何处理它们。然后 - 今天早上我收到了关于你评论的 SO 通知。严重惊悚!但是谢谢你!:-) (3认同)
  • @Shaul:我不认为这是不可能的。John Skeet 在 SO 方面颇受尊敬,建议将生成的实例存储在他对基本相同问题的回答中:http://stackoverflow.com/a/10151804/155268 (2认同)

Kri*_*ler 17

您可能希望查看iCalendar软件实现或标准本身(RFC 2445 RFC 5545).Mozilla项目很快就会浮现在脑海中http://www.mozilla.org/projects/calendar/ 快速搜索显示http://icalendar.rubyforge.org/.

可以考虑其他选项,具体取决于您将如何存储事件.您是否正在构建自己的数据库架构?使用基于iCalendar的东西等?

  • 看起来RFC2445已被RFC5545淘汰(http://tools.ietf.org/html/rfc5545) (7认同)

Vee*_*Vee 16

我正在使用以下内容:

还有一个正在进行的宝石,它使用输入类型扩展了formtastic:recurring(form.schedule :as => :recurring),它呈现类似iCal的界面,before_filter并将视图IceCube再次序列化为一个对象,ghetto-ly.

我的想法是让向模型添加重复属性并在视图中轻松连接它变得难以置信.一切都在几行.


那给了我什么呢?索引,可编辑,重复属性.

events存储单日实例,并在日历视图/帮助器中使用,例如task.schedule存储yaml'd IceCube对象,因此您可以执行以下调用:task.schedule.next_suggestion.

回顾:我使用两个模型,一个平面,用于日历显示,一个属性用于功能.


Bri*_*kau 15

我开发了多个基于日历的应用程序,还编写了一组支持重复发生的可重用JavaScript日历组件.我写了一篇关于如何设计可能对某人有帮助的重现的概述.虽然有一些特定于我编写的库的位,但提供的绝大多数建议对于任何日历实现都是通用的.

一些关键点:

  • 使用iCal RRULE格式存储重复- 这是你真正不想重新发明的一个轮子
  • 不要将单个定期事件实例存储为数据库中的行!始终存储重复发生模式.
  • 有许多方法可以设计事件/异常模式,但提供了一个基本的起点示例
  • 所有日期/时间值都应以UTC格式存储并转换为本地值以供显示
  • 为周期性事件存储的结束日期应始终为重复范围结束日期(如果"永久"重复,则应为平台的"最大日期"),并且事件持续时间应单独存储.这是为了确保以后查询事件的理智方式.
  • 包括有关生成事件实例和重复编辑策略的一些讨论

这是一个非常复杂的主题,有很多很多有效的方法来实现它.我会说我实际上已经多次成功实施了复发,而且我会警惕从没有实际做过这个问题的人那里接受这个问题的建议.

  • @BrianMoeskau 但是,当有人在某些事件已经发生后编辑 RRULE 时,您的日历的过去视图不会显示不准确的信息吗?或者也许在这种情况下,您会“分支”RRULE 并保留代表过去实际发生情况的 RRULE 模式的修改版本? (2认同)
  • @BrianMoeskau 另一点,关于在 UTC 中存储并转换为本地显示:我同意这是一般的最佳实践,但如果您有一个涉及夏令时变化的重复事件,它不会中断吗?我的意思是:如果我们以 UTC 为基础进行所有计算,那么“每周一上午 8 点当地时间”(这可能是用户想要的)将变成“周一上午 9 点当地 DST”(对于典型的 DST 更改 - 或者相反)如果该条目实际上是在 DST 期间创建的,则 DST 结束)。我在这里错过了什么吗? (2认同)
  • @Brian Moeskau 我住的地方,当地时间是 UTC-3。假设我创建一个活动“当地时间每周一 8:00”;它将被存储为“11:00Z”。夏令时到来,当地时间更改为 UTC-2。该事件现在将从数据库中恢复为“11:00Z”==“9:00 UTC-2”(我的夏令时当地时间),这不是我想要的(我想要当地时间 8:00,无论夏令时如何) )。注意:如果我在 DST (8:00 UTC-2) 期间创建事件,数据库记录将为“10:00Z”,DST 结束后将恢复为“7:00 UTC-3”(同样,不是什么)我想了)。 (2认同)

lia*_*zan 6

我正在使用如下所述的数据库模式来存储重复参数

http://github.com/bakineggs/recurring_events_for

然后我用runt动态计算日期.

https://github.com/mlipper/runt


bdu*_*kes 5

  1. 跟踪重复规则(可能基于iCalendar,基于@ Kris K.)。这将包括模式和范围(每第三个星期二,出现10次)。
  2. 因为当你想编辑/删除发生的特定事件,追踪例外日期为上述复发规则(日期该事件不会发生因为规则规定)。
  3. 如果删除了,那就足够了,如果您进行编辑,则可以创建另一个事件,并将其父ID设置为主要事件。您可以选择是在该记录中包括所有主事件的信息,还是仅保留更改并继承所有未更改的信息。

请注意,如果您允许不终止的重复规则,则必须考虑如何显示现在无限量的信息。

希望有帮助!