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


224

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

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

(我使用的是Ruby,但是请不要让它限制您的答案。但是,如果有特定于Ruby的库之类的东西,那很高兴知道。)

Answers:


93

我会在以后的所有重复事件中使用“链接”概念。它们将动态显示在日历中,并链接回单个参考对象。事件发生后,链接断开,该事件成为独立实例。如果您尝试编辑重复发生的事件,则提示您更改所有将来的项目(即更改单个链接的引用)或仅更改该实例(在这种情况下,将其转换为独立实例,然后进行更改)。后者的情况有点问题,因为您需要跟踪所有转换为单个实例的将来事件的重复列表。但是,这完全是可行的。

因此,从本质上讲,有2类事件-单个实例和重复发生的事件。


真的很像您在事件经过后将事件链接并转换为独立事件的想法。两个问题:-为什么要将它们完全转换为独立的固定实例?为什么不让它们保持完全动态?-您可以共享建议的链接概念的参考!提前致谢!
rtindru '17

@rtindru我发现一个将事件转换为独立事件的用例是当您必须将事件模型与数据库中的其他模型一起使用时。例如,用于检查事件的出勤率,您将需要将用户与发生(或将要发生)的真实事件相关联。
希拉里·伊波亚


33

重复发生的事件可能会有很多问题,让我强调一些我所知道的问题。

解决方案1-没有实例

存储原始约会和重复数据,而不存储所有实例。

问题:

  • 需要时,您必须在日期窗口中计算所有实例,这很昂贵
  • 无法处理异常(即,您删除一个实例,或将其移动,或者,您无法使用此解决方案来执行此操作)

解决方案2-存储实例

存储从1开始的所有内容,还存储所有实例,链接回原始约会。

问题:

  • 占用大量空间(但是空间便宜,所以较小)
  • 必须妥善处理异常,特别是如果您在产生异常后返回并编辑原始约会时,尤其如此。例如,如果您将第三个实例向前移动一天,那么如果您回去编辑原始约会的时间,然后在原始日期重新插入另一个并留下移动的日期,该怎么办?取消移动的链接?尝试适当地更改已移动的?

当然,如果您不打算做例外,那么任何一种解决方案都应该是好的,并且您基本上可以从时间/空间折衷方案中进行选择。


36
如果您有一个没有结束日期的定期约会怎么办?尽管空间便宜,但您没有无限的空间,因此解决方案2根本无法满足需求……
Shaul Behr

13
解决方案1实际上可以处理异常。例如,RFC5545建议将它们存储为:a)排除日期列表(删除事件时);b)引用原型的“物化”事件(移动事件时)。
2011年

@ Andy,Lasse答案的一些有趣的补充。要尝试一下。
乔纳森·威尔逊

1
@Shaul:我不认为这不是一个入门者。John Skeet在SO方面非常受人尊敬,他建议将生成的实例存储在他对基本相同的问题的回答中:stackoverflow.com/a/10151804/155268
用户

1
@User-确认,谢谢。太奇怪了-我在4年前发表了自己的评论,从那时起,我真的不需要处理这个问题。就在昨天,我开始设计一个涉及定期约会的新模块,我想知道如何处理它们。然后-今天早上我收到了您的评论的通知。严重的恐怖!但是谢谢你!:-)
Shaul Behr

20

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

一些关键点:

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

这是一个非常复杂的主题,有很多有效的实现方法。我要说的是,我实际上已经成功地成功实施了多次递归治疗,因此我会谨慎地向尚未真正做到这一点的任何人征求意见。


也许当事件发生时将重复存储为事件,以便您的日历历史记录准确
Richard Haven

@RichardHaven我永远不会那样做。您应该始终从过去,现在或将来从RRULE模式生成实例。没有理由对历史事件做些不同的事情。您的逻辑应该只针对任意日期范围评估RRULE并返回匹配的事件实例。
布莱恩·莫斯考

@BrianMoeskau不错而有用的概述!
Przemek Nowak,

@BrianMoeskau但是,当某些情况发生后有人编辑RRULE时,过去的日历视图不会显示不正确的信息吗?还是在那种情况下,您将“分支” RRULE并保留代表实际过去实际发生的RRULE模式的修改版本?
基督教徒

1
@christian当您更新大多数日历中的重复规则时,它们通常会提示诸如“编辑所有事件,或者仅此事件,或仅将来”,以允许用户选择行为。在大多数情况下,用户可能表示“不断更改”,但还是要由您决定软件的工作方式以及为用户提供的选项。
布莱恩·莫斯考

19

您可能需要查看iCalendar软件实现或标准本身(RFC 2445 RFC 5545)。很快就会想到的是Mozilla项目http://www.mozilla.org/projects/calendar/ 快速搜索也显示了http://icalendar.rubyforge.org/

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


如果您仅可以提供这些链接之一,那么您的帖子将是完美的
Jean

7
看起来RFC2445已被RFC5545(tools.ietf.org/html/rfc5545)作废了
Eric Freese 2010年

16

我正在处理以下内容:

以及一个进行中的宝石,它使用输入类型:recurring(form.schedule :as => :recurring)扩展形式,这呈现了类似于iCal的界面,并且before_filter将视图IceCube再次贫民窟地序列化为对象。

我的想法是使添加循环属性到模型并在视图中轻松连接变得容易。共有两行。


那这给我什么呢?索引的,可编辑的循环属性。

events店单日的实例,并在日历视图中使用/助手说task.schedule存储yaml'd IceCube对象,所以你可以像电话:task.schedule.next_suggestion

回顾:我使用两种模型,一种用于日历显示,而另一种用于功能。


我很想知道您的想法。您在任何地方都有git / blog /概念证明吗?谢谢!
蒙特利尔

我也在做类似的事情。希望看到您的执行情况
Thoughtpunch


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

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

希望有帮助!


4

我建议使用日期库的功能以及ruby的range模块的语义。重复发生的事件实际上是一个时间,一个日期范围(开始和结束),通常是一周中的一天。使用日期和范围,您可以回答任何问题:

#!/usr/bin/ruby
require 'date'

start_date = Date.parse('2008-01-01')
end_date   = Date.parse('2008-04-01')
wday = 5 # friday

(start_date..end_date).select{|d| d.wday == wday}.map{|d| d.to_s}.inspect

产生事件的所有日子,包括 the年!

# =>"[\"2008-01-04\", \"2008-01-11\", \"2008-01-18\", \"2008-01-25\", \"2008-02-01\", \"2008-02-08\", \"2008-02-15\", \"2008-02-22\", \"2008-02-29\", \"2008-03-07\", \"2008-03-14\", \"2008-03-21\", \"2008-03-28\"]"

2
这不是很灵活。重复事件模型通常需要指定重复周期(每小时,每周,每两周等)。此外复发可能无法通过总数,而结束日期为最后出现的资格
博Jeanes

“重复发生的事件是[..]通常一周中的一天”,这仅仅是一个有限的使用情况下,不会处理许多其他如“每月”等的第5天
theraven

3

从这些答案中,我找到了一个解决方案。我真的很喜欢链接概念的想法。重复发生的事件可能是一个链表,尾巴知道其重复发生的规则。这样,更改一个事件将很容易,因为链接保持不变,并且删除事件也很容易-您只需取消链接事件,将其删除,然后在事件之前和之后将其重新链接即可。每当有人查看日历上从未见过的新时间段时,您仍然必须查询重复发生的事件,但是这样做很干净。


2

您可以将事件存储为重复事件,如果已编辑特定实例,则使用相同的事件ID创建一个新事件。然后,在查找事件时,搜索具有相同事件ID的所有事件以获取所有信息。我不确定您是否滚动了自己的事件库,或者是否正在使用现有的事件库,因此可能无法实现。


我曾经使用过这种解决方案。我喜欢将修改后的实例存储为新的一次性事件的原理,该事件知道其妈妈是谁。这样,您可以将所有字段保留为空,但子事件中的字段除外。请注意,您将必须有一个额外的字段,用于指定您正在编辑的该母亲的哪个孩子。
Wytze 2012年


1

在javascript中:

处理定期计划:http//bunkat.github.io/later/

处理这些计划之间的复杂事件和依赖性:http : //bunkat.github.io/schedule/

基本上,先创建规则,然后要求lib计算下N个重复发生的事件(是否指定​​日期范围)。可以对规则进行解析/序列化,以将其保存到模型中。

如果您有一个重复发生的事件,并且只想修改一次重复发生,则可以使用exception()函数关闭某一天,然后为该条目添加一个新的修改后的事件。

该库支持非常复杂的模式,时区甚至是croning事件。


0

将事件存储为重复事件并动态显示它们,但是允许重复发生的事件包含特定事件的列表,这些列表可能会覆盖特定日期的默认信息。

当您查询重复事件时,它可以检查当天的特定替代。

如果用户进行了更改,则可以询问他是要针对所有实例(默认详细信息)还是仅针对当天(进行新的特定事件并将其添加到列表中)进行更新。

如果用户要求删除此事件的所有重复发生,那么您还可以获取详细信息列表,并且可以轻松删除它们。

唯一有问题的情况是用户是否要更新此事件以及所有将来的事件。在这种情况下,您必须将重复事件分为两部分。此时,您可能需要考虑以某种方式链接重复发生的事件,以便将其全部删除。


0

对于准备支付一些许可费用的.NET程序员,您可能会发现Aspose.Network有用...它包括一个iCalendar兼容库,用于定期约会。


0

您可以将事件直接以iCalendar格式存储,从而可以进行开放式重复,时区本地化等等。

您可以将它们存储在CalDAV服务器中,然后在要显示事件时,可以使用CalDAV中定义的报告选项来要求服务器在查看期间扩展重复发生的事件。

或者,您也可以自己将它们存储在数据库中,并使用某种iCalendar解析库进行扩展,而无需PUT / GET / REPORT与后端CalDAV服务器对话。这可能是更多的工作-我确信CalDAV服务器会将复杂性隐藏在某个地方。

从长远来看,采用iCalendar格式的事件可能会使事情变得更简单,因为人们总是希望将其导出以放入其他软件中。


0

我已经实现了此功能!逻辑如下,首先需要两个表。RuleTable存储常规事件或回收父事件。ItemTable是存储周期事件。例如,当您创建循环事件时,开始时间为2015年11月6日,结束时间为12月6日(或永远),周期为一周。您将数据插入RuleTable中,字段如下:

TableID: 1 Name: cycleA  
StartTime: 6 November 2014 (I kept thenumber of milliseconds),  
EndTime: 6 November 2015 (if it is repeated forever, and you can keep the value -1) 
Cycletype: WeekLy.

现在,您要查询11月20日至12月20日的数据。您可以根据开始时间和结束时间WeekLy编写函数RecurringEventBE(长起点,长终点),可以计算所需的集合<cycleA11.20,cycleA 11.27,cycleA 12.4 ......>。除了11月6日,其余的我都称他为虚拟活动。当用户之后更改虚拟事件的名称(例如,cycleA11.27)时,可以将数据插入到ItemTable中。字段如下:

TableID: 1 
Name, cycleB  
StartTime, 27 November 2014  
EndTime,November 6 2015  
Cycletype, WeekLy
Foreignkey, 1 (pointingto the table recycle paternal events).

在函数RecurringEventBE(长起点,长终点)中,您使用了覆盖虚拟事件的数据(cycleB11.27),对不起我的英语,我尝试了。

这是我的RecurringEventBE:

public static List<Map<String, Object>> recurringData(Context context,
        long start, long end) { // 重复事件的模板处理,生成虚拟事件(根据日期段)
     long a = System.currentTimeMillis();
    List<Map<String, Object>> finalDataList = new ArrayList<Map<String, Object>>();

    List<Map<String, Object>> tDataList = BillsDao.selectTemplateBillRuleByBE(context); //RuleTablejust select recurringEvent
    for (Map<String, Object> iMap : tDataList) {

        int _id = (Integer) iMap.get("_id");
        long bk_billDuedate = (Long) iMap.get("ep_billDueDate"); // 相当于事件的开始日期 Start
        long bk_billEndDate = (Long) iMap.get("ep_billEndDate"); // 重复事件的截止日期 End
        int bk_billRepeatType = (Integer) iMap.get("ep_recurringType"); // recurring Type 

        long startDate = 0; // 进一步精确判断日记起止点,保证了该段时间断获取的数据不未空,减少不必要的处理
        long endDate = 0;

        if (bk_billEndDate == -1) { // 永远重复事件的处理

            if (end >= bk_billDuedate) {
                endDate = end;
                startDate = (bk_billDuedate <= start) ? start : bk_billDuedate; // 进一步判断日记起止点,这样就保证了该段时间断获取的数据不未空
            }

        } else {

            if (start <= bk_billEndDate && end >= bk_billDuedate) { // 首先判断起止时间是否落在重复区间,表示该段时间有重复事件
                endDate = (bk_billEndDate >= end) ? end : bk_billEndDate;
                startDate = (bk_billDuedate <= start) ? start : bk_billDuedate; // 进一步判断日记起止点,这样就保证了该段时间断获取的数据不未空
            }
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(bk_billDuedate); // 设置重复的开始日期

        long virtualLong = bk_billDuedate; // 虚拟时间,后面根据规则累加计算
        List<Map<String, Object>> virtualDataList = new ArrayList<Map<String, Object>>();// 虚拟事件

        if (virtualLong == startDate) { // 所要求的时间,小于等于父本时间,说明这个是父事件数据,即第一条父本数据

            Map<String, Object> bMap = new HashMap<String, Object>();
            bMap.putAll(iMap);
            bMap.put("indexflag", 1); // 1表示父本事件
            virtualDataList.add(bMap);
        }

        long before_times = 0; // 计算从要求时间start到重复开始时间的次数,用于定位第一次发生在请求时间段落的时间点
        long remainder = -1;
        if (bk_billRepeatType == 1) {

            before_times = (startDate - bk_billDuedate) / (7 * DAYMILLIS);
            remainder = (startDate - bk_billDuedate) % (7 * DAYMILLIS);

        } else if (bk_billRepeatType == 2) {

            before_times = (startDate - bk_billDuedate) / (14 * DAYMILLIS);
            remainder = (startDate - bk_billDuedate) % (14 * DAYMILLIS);

        } else if (bk_billRepeatType == 3) {

            before_times = (startDate - bk_billDuedate) / (28 * DAYMILLIS);
            remainder = (startDate - bk_billDuedate) % (28 * DAYMILLIS);

        } else if (bk_billRepeatType == 4) {

            before_times = (startDate - bk_billDuedate) / (15 * DAYMILLIS);
            remainder = (startDate - bk_billDuedate) % (15 * DAYMILLIS);

        } else if (bk_billRepeatType == 5) {

            do { // 该段代码根据日历处理每天重复事件,当事件比较多的时候效率比较低

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH, 1);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 1 + 1);
                    virtualLong = calendar.getTimeInMillis();
                } else {
                    calendar.add(Calendar.MONTH, 1);
                    virtualLong = calendar.getTimeInMillis();
                }

            } while (virtualLong < startDate);

        } else if (bk_billRepeatType == 6) {

            do { // 该段代码根据日历处理每天重复事件,当事件比较多的时候效率比较低

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH, 2);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 2 + 2);
                    virtualLong = calendar.getTimeInMillis();
                } else {
                    calendar.add(Calendar.MONTH, 2);
                    virtualLong = calendar.getTimeInMillis();
                }

            } while (virtualLong < startDate);

        } else if (bk_billRepeatType == 7) {

            do { // 该段代码根据日历处理每天重复事件,当事件比较多的时候效率比较低

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH, 3);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 3 + 3);
                    virtualLong = calendar.getTimeInMillis();
                } else {
                    calendar.add(Calendar.MONTH, 3);
                    virtualLong = calendar.getTimeInMillis();
                }

            } while (virtualLong < startDate);

        } else if (bk_billRepeatType == 8) {

            do {
                calendar.add(Calendar.YEAR, 1);
                virtualLong = calendar.getTimeInMillis();
            } while (virtualLong < startDate);

        }

        if (remainder == 0 && virtualLong != startDate) { // 当整除的时候,说明当月的第一天也是虚拟事件,判断排除为父本,然后添加。不处理,一个月第一天事件会丢失
            before_times = before_times - 1;
        }

        if (bk_billRepeatType == 1) { // 单独处理天事件,计算出第一次出现在时间段的事件时间

            virtualLong = bk_billDuedate + (before_times + 1) * 7
                    * (DAYMILLIS);
            calendar.setTimeInMillis(virtualLong);

        } else if (bk_billRepeatType == 2) {

            virtualLong = bk_billDuedate + (before_times + 1) * (2 * 7)
                    * DAYMILLIS;
            calendar.setTimeInMillis(virtualLong);
        } else if (bk_billRepeatType == 3) {

            virtualLong = bk_billDuedate + (before_times + 1) * (4 * 7)
                    * DAYMILLIS;
            calendar.setTimeInMillis(virtualLong);
        } else if (bk_billRepeatType == 4) {

            virtualLong = bk_billDuedate + (before_times + 1) * (15)
                    * DAYMILLIS;
            calendar.setTimeInMillis(virtualLong);
        }

        while (startDate <= virtualLong && virtualLong <= endDate) { // 插入虚拟事件
            Map<String, Object> bMap = new HashMap<String, Object>();
            bMap.putAll(iMap);
            bMap.put("ep_billDueDate", virtualLong);
            bMap.put("indexflag", 2); // 2表示虚拟事件
            virtualDataList.add(bMap);

            if (bk_billRepeatType == 1) {

                calendar.add(Calendar.DAY_OF_MONTH, 7);

            } else if (bk_billRepeatType == 2) {

                calendar.add(Calendar.DAY_OF_MONTH, 2 * 7);

            } else if (bk_billRepeatType == 3) {

                calendar.add(Calendar.DAY_OF_MONTH, 4 * 7);

            } else if (bk_billRepeatType == 4) {

                calendar.add(Calendar.DAY_OF_MONTH, 15);

            } else if (bk_billRepeatType == 5) {

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH,
                        1);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 1
                            + 1);
                } else {
                    calendar.add(Calendar.MONTH, 1);
                }

            }else if (bk_billRepeatType == 6) {

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH,
                        2);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 2
                            + 2);
                } else {
                    calendar.add(Calendar.MONTH, 2);
                }

            }else if (bk_billRepeatType == 7) {

                Calendar calendarCloneCalendar = (Calendar) calendar
                        .clone();
                int currentMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);
                calendarCloneCalendar.add(Calendar.MONTH,
                        3);
                int nextMonthDay = calendarCloneCalendar
                        .get(Calendar.DAY_OF_MONTH);

                if (currentMonthDay > nextMonthDay) {
                    calendar.add(Calendar.MONTH, 3
                            + 3);
                } else {
                    calendar.add(Calendar.MONTH, 3);
                }

            } else if (bk_billRepeatType == 8) {

                calendar.add(Calendar.YEAR, 1);

            }
            virtualLong = calendar.getTimeInMillis();

        }

        finalDataList.addAll(virtualDataList);

    }// 遍历模板结束,产生结果为一个父本加若干虚事件的list

    /*
     * 开始处理重复特例事件特例事件,并且来时合并
     */
    List<Map<String, Object>>oDataList = BillsDao.selectBillItemByBE(context, start, end);
    Log.v("mtest", "特例结果大小" +oDataList );


    List<Map<String, Object>> delectDataListf = new ArrayList<Map<String, Object>>(); // finalDataList要删除的结果
    List<Map<String, Object>> delectDataListO = new ArrayList<Map<String, Object>>(); // oDataList要删除的结果


    for (Map<String, Object> fMap : finalDataList) { // 遍历虚拟事件

        int pbill_id = (Integer) fMap.get("_id");
        long pdue_date = (Long) fMap.get("ep_billDueDate");

        for (Map<String, Object> oMap : oDataList) {

            int cbill_id = (Integer) oMap.get("billItemHasBillRule");
            long cdue_date = (Long) oMap.get("ep_billDueDate");
            int bk_billsDelete = (Integer) oMap.get("ep_billisDelete");

            if (cbill_id == pbill_id) {

                if (bk_billsDelete == 2) {// 改变了duedate的特殊事件
                    long old_due = (Long) oMap.get("ep_billItemDueDateNew");

                    if (old_due == pdue_date) {

                        delectDataListf.add(fMap);//该改变事件在时间范围内,保留oMap

                    }

                } else if (bk_billsDelete == 1) {

                    if (cdue_date == pdue_date) {

                        delectDataListf.add(fMap);
                        delectDataListO.add(oMap);

                    }

                } else {

                    if (cdue_date == pdue_date) {
                        delectDataListf.add(fMap);
                    }

                }

            }
        }// 遍历特例事件结束

    }// 遍历虚拟事件结束
    // Log.v("mtest", "delectDataListf的大小"+delectDataListf.size());
    // Log.v("mtest", "delectDataListO的大小"+delectDataListO.size());
    finalDataList.removeAll(delectDataListf);
    oDataList.removeAll(delectDataListO);
    finalDataList.addAll(oDataList);
    List<Map<String, Object>> mOrdinaryList = BillsDao.selectOrdinaryBillRuleByBE(context, start, end);
    finalDataList.addAll(mOrdinaryList);
    // Log.v("mtest", "finalDataList的大小"+finalDataList.size());
    long b = System.currentTimeMillis();
    Log.v("mtest", "算法耗时"+(b-a));

    return finalDataList;
}   

-5

如果您有一个没有结束日期的定期约会怎么办?尽管空间便宜,但您没有无限的空间,因此解决方案2在这里是不入门的...

我可以建议将“无结束日期”解析为本世纪末的结束日期。即使对于日常活动,空间量仍然很便宜。


7
我们怎么会忘记y2k的教训... :)
Ian Mercer

10
假设我们有1000个用户,每个用户都有一些日常事件。3个事件×1000个用户×365天×(2100-2011 = 89年)= 9750万记录 而不是3000个“计划”。嗯...
Andy Mikhaylenko 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.