Frage

Ich baue eine Gruppenkalender-Anwendung, die wiederkehrenden Ereignisse unterstützen muß, aber alle Lösungen, die ich habe kommen mit diesen Ereignissen scheinen wie ein Hack zu behandeln. Ich kann begrenzen, wie weit voraus kann man suchen, und dann alle Ereignisse auf einmal erzeugen. Oder ich kann die Ereignisse speichern, wie wiederholen und sie dynamisch angezeigt werden, wenn man schaut nach vorn auf dem Kalender, aber ich muß sie in einem normalen Ereignisse umwandeln, wenn jemand will, um die Details zu einer bestimmten Instanz des Ereignisses ändern.

Ich bin sicher, es gibt einen besseren Weg, dies zu tun, aber ich habe es noch nicht gefunden. Was ist der beste Weg, wiederkehrende Ereignisse zu modellieren, in dem Sie Details oder löschen bestimmte Ereignisinstanzen ändern?

(Ich bin mit Ruby, aber bitte lassen Sie sich nicht, dass Ihre Antwort beschränken. Wenn es eine Ruby-spezifische Bibliothek ist oder etwas, aber das ist gut zu wissen.)

War es hilfreich?

Lösung

würde ich eine ‚Verbindung‘ Konzept für alle künftigen wiederkehrende Ereignisse verwenden. Sie sind dynamisch im Kalender angezeigt und verlinkt auf ein einziges Referenzobjekt zurück. Wenn Ereignisse stattgefunden haben, ist die Verbindung unterbrochen und das Ereignis wird zu einer eigenständigen Instanz. Wenn Sie ein wiederkehrendes Ereignis dann prompt zu bearbeiten versuchen, alle zukünftigen Elemente ändern (das heißt einzelne verknüpften Referenz ändern) oder nur die Instanz ändern (in diesem Fall wandeln diese in eine eigenständige Instanz und dann Änderung vornehmen). Letztere verrohrt ist etwas problematisch, da Sie den Überblick in Ihrem wiederkehrend Liste aller zukünftigen Ereignisse halten müssen, die einzelne Instanz umgewandelt wurden. Aber dies ist völlig tun können.

Also, im Grunde hat zwei Klassen von Ereignissen -. Einzel Instanzen und wiederkehrenden Ereignissen

Andere Tipps

Martin Fowler -. Events für Kalender Recurring enthält einige interessante Einblicke und Muster

Runt gem implementiert diese Muster.

Es kann viele Probleme mit wiederkehrenden Ereignissen sein, lassen Sie mich ein paar hervorheben, die ich kenne.

Lösung 1 - keine Instanzen

Speichern ursprünglichen Termin + Wiederholung Daten nicht speichern alle Instanzen.

Probleme:

  • Sie müssen, um alle Instanzen in einem Datumsfenster zu berechnen, wenn man sie braucht, teuer
  • Können Sie Ausnahmen behandeln (dh. Sie eine der Instanzen löschen oder verschieben, oder besser gesagt, können Sie dies mit dieser Lösung nicht tun)

Lösung 2 - Öffnungs Instanzen

Shop alles von 1, sondern auch alle Instanzen, wieder auf den ursprünglichen Termin verknüpft.

Probleme:

  • nimmt viel Platz (aber Raum ist billig, so minor)
  • Ausnahmen müssen ordnungsgemäß gehandhabt werden, vor allem wenn man den ursprünglichen Termin zurückgehen und bearbeiten, nachdem eine Ausnahme zu machen. Zum Beispiel, wenn Sie den dritten Instanz eines Tages vor, was passiert, wenn Sie zurück gehen und die Zeit des ursprünglichen Termins bearbeiten, wieder einsetzen eine weitere auf dem ursprünglichen Tag und die verschobene eine verlassen? Unlink die verschobene ein? Versuchen Sie, die bewegt man in geeigneter Weise zu ändern?

Natürlich, wenn Sie nicht Ausnahmen gehen zu tun, dann sollte entweder Lösung in Ordnung sein, und man im Grunde aus einem Zeit / Raum-Trade-off-Szenario wählen.

Sie möchten bei iCalendar Softwareimplementierungen oder der Standard selbst ( RFC 2445 RFC 5545 ). Ones in den Sinn zu kommen schnell sind die Mozilla-Projekte http://www.mozilla.org/projects/calendar/ Eine schnelle Suche zeigt http://icalendar.rubyforge.org/ auch.

Weitere Optionen können je nach in Betracht gezogen werden, wie du gehst, die Ereignisse zu speichern. Bauen Sie Ihre eigene Datenbank-Schema? Mit etwas iCalendar-basierter, etc.?

Ich arbeite mit dem folgenden:

und ein Edelstein in Fortschritten, die mit einem Eingangstyp formtastic erstreckt. Wiederkehrende (form.schedule :as => :recurring), die eine iCal-ähnliche Oberfläche und einem before_filter rendert die Ansicht in ein IceCube Objekt serialisieren wieder getto-Ly

Meine Idee ist es Unglaubwürdigkeit leicht zu machen Attribute zu einem Modell hinzufügen wiederkehrenden und leicht in der Ansicht anschließen. Alles in ein paar Zeilen.


Was bedeutet dies mir geben? Indexiert, bearbeiten können, Recurring Attribute.

events speichert einen einzigen Tag Instanz und wird in der Kalenderansicht / Helfer verwendet sagen task.schedule speichert die yaml'd IceCube Objekt, so dass Sie Anrufe wie tun können:. task.schedule.next_suggestion

Recap: Ich verwende zwei Modelle, eine Wohnung, in der Kalenderanzeige und eine attribute'd für die Funktionalität

.

Ich habe mehrere Kalender-basierte Anwendungen entwickelt und verfasste auch eine Reihe von wieder verwendbaren JavaScript Kalender-Komponenten, die Wiederholung unterstützen. Ich schrieb auf einen Überblick über wie für eine Wiederholung entwerfen das könnte hilfreich sein, um jemanden. Zwar gibt es ein paar Bits, die in der Bibliothek spezifisch ich schrieb, bot die überwiegende Mehrheit der Beratung ist allgemein Kalender Umsetzung.

Einige der wichtigsten Punkte:

  • Speichern Wiederholung der iCal RRULE Format mit - das ist ein Rad Sie wirklich will nicht neu zu erfinden
  • Speichern Sie keine einzelne wiederkehrendes Ereignis Instanzen als Zeilen in der Datenbank! Speichern Sie immer ein Wiederholungsmuster.
  • Es gibt viele Möglichkeiten, um Ihre Veranstaltung / Ausnahme-Schema zu entwerfen, sondern eine grundlegende Ausgangspunkt Beispiel wird bereitgestellt,
  • Alle Datums- / Zeitwerte in UTC gespeichert werden soll und umgerechnet für die Anzeige auf lokale
  • Die für ein wiederkehrendes Ereignis gespeichert Enddatum sollte immer die Enddatum des erneuten Auftretens Bereich (oder „max date“ der Plattform, wenn „für immer“ wiederkehrend) und die Ereignisdauer separat gespeichert werden . Dies ist später eine gesunde Art und Weise der Abfrage für Veranstaltungen zu gewährleisten.
  • Einige Diskussion um Erzeugen von Ereignisinstanzen und Wiederholung Bearbeitungsstrategien enthalten ist

Es ist ein wirklich kompliziertes Thema mit vielen, es vielen gültigen Ansätzen zur Umsetzung. Ich werde sagen, dass ich tatsächlich mehrmals erfolgreich Wiederholung implementiert habe, und ich würde von einem der Einnahme Beratung zu diesem Thema vorsichtig sein, die es eigentlich nicht getan hat.

Ich bin mit dem Datenbank-Schema, wie unten beschrieben, um die Wiederholung Parameter speichern

http://github.com/bakineggs/recurring_events_for

Dann benutze ich Runt, um dynamisch die Daten zu berechnen.

https://github.com/mlipper/runt

  1. Behalte eine Wiederholungsregel (wahrscheinlich auf iCalendar, pro @ Kris K. ). Dies wird ein Muster umfassen und einen Bereich (jeden dritten Dienstag, 10 Fälle).
  2. Für, wenn Sie ein bestimmtes Ereignis zu bearbeiten / löschen, verfolgen Ausnahme Termine für die oben Wiederholungsregel (Termine, wo das Ereignis nicht auftreten, wie die Regel gibt).
  3. Wenn Sie gelöscht, das ist alles, was Sie brauchen, wenn Sie ein anderes Ereignis bearbeitet, erstellen und ihm ein übergeordneten ID-Set für den Main Event geben. Sie können wählen, ob alle Hauptereignis der Informationen in diesem Bericht aufzunehmen, oder wenn es nur die Änderungen hält und erbt alles, was sich nicht verändert.

Beachten Sie, wenn Sie Wiederholungsregeln zulassen, dass Sie am Ende nicht, zu denken, wie Ihre jetzt unendliche Menge an Informationen angezeigt werden.

Ich hoffe, das hilft!

Ich würde empfehlen, die Macht der aktuellen Bibliothek und die Semantik des Bereichsmodul von Rubin verwenden. Ein wiederkehrendes Ereignis ist wirklich eine Zeit, ein Datumsbereich (Start- und Ende) und in der Regel nur einen einzigen Tag der Woche. Mit Datum & Bereich können Sie jede Frage beantworten:

#!/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

Erzeugt alle Tage der Veranstaltung, mit das Schaltjahr!

# =>"[\"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\"]"

Aus diesen Antworten, habe ich irgendwie eine Lösung ausgesiebt. Ich mag die Idee des Link-Konzept. Wiederkehrende Ereignisse könnten eine verknüpfte Liste, mit dem Schwanz seine Wiederholungsregel zu wissen sein. ein Ereignis ändern würde dann einfach sein, weil die Links an ihrem Platz bleiben, und ein Ereignis zu löschen ist auch einfach - man muss nur ein Ereignis entkoppeln, löschen und neu verknüpft das Ereignis vor und nach ihm. Sie müssen immer noch wiederkehrende Ereignisse abfragen, jedes Mal, wenn jemand in einer neuen Zeitperiode sieht nie zuvor auf dem Kalender betrachtet worden, aber ansonsten das ist ziemlich sauber.

Sie können die Ereignisse speichern, wie wiederholen, und wenn eine bestimmte Instanz bearbeitet wurde, ein neues Ereignis mit der gleichen Ereignis-ID erstellen. Dann, wenn das Ereignis aufzublicken, Suche für alle Veranstaltungen mit der gleichen Ereignis-ID erhalten Sie alle Informationen. Ich bin mir nicht sicher, ob Sie Ihre eigene Veranstaltung Bibliothek gerollt, oder wenn Sie ein vorhandenes verwenden, so kann es nicht möglich sein.

die Artikel Unten finden Sie drei gute rubin Datum / Zeit-Bibliotheken. ice_cube insbesondere scheint eine gute Wahl für Wiederholungsregeln und andere Sachen, die ein Event Kalender benötigen würde. http://www.rubyinside.com /3-new-date-and-time-libraries-for-rubyists-3238.html

In javascript:

Handling wiederkehrende Zeitplan: http://bunkat.github.io/later/

Handhabung komplexe Ereignisse und Abhängigkeiten zwischen diesen Zeitplan: http://bunkat.github.io/schedule/

Im Grunde erstellen Sie die Regeln dann fragen Sie die lib die nächsten N wiederkehrende Ereignisse zu berechnen (einen Datumsbereich oder nicht spezifiziert). Die Regeln können sie in das Modell für das Speichern analysiert / serialisiert werden.

Wenn Sie ein wiederkehrendes Ereignis und möchten nur eine Wiederholung ändern können Sie die mit Ausnahme von () verwenden Funktion einen bestimmten Tag zu entlassen und dann ein neues modifizierte Ereignis für diesen Eintrag hinzufügen .

Die lib unterstützt sehr komplexe Muster, Zeitzonen und sogar Croning Ereignisse.

die Ereignisse speichern als Wiederholung und sie dynamisch angezeigt werden, aber die wiederkehrendes Ereignis ermöglichen eine Liste bestimmter Ereignisse zu enthalten, die die Standardinformationen an einem bestimmten Tag außer Kraft setzen können.

Wenn Sie das wiederkehrende Ereignis abfragen kann es für diesen Tag für eine bestimmte Überschreibung.

Wenn ein Benutzer Änderungen vornimmt, dann kann man fragen, ob er für alle Instanzen (default) oder bei gerade diesem Tag (machen ein neues bestimmtes Ereignis und fügen Sie ihn in der Liste) aktualisieren will.

Wenn ein Benutzer bittet alle Rezidive dieses Ereignisses löschen Sie auch die Liste der Besonderheiten zur Hand und können sie leicht entfernen.

Der einzige problematische Fall wäre, wenn der Benutzer dieses Ereignis aktualisieren will und alle zukünftigen Ereignisse. In diesem Fall sehen Sie das wiederkehrende Ereignis in zwei haben aufzuspalten. An dieser Stelle möchten Sie vielleicht die Verknüpfung wiederkehrende Ereignisse in irgendeiner Weise zu berücksichtigen, so dass Sie sie alle löschen.

Für .NET-Programmierer, die bereit sind, ein paar Lizenzgebühren zu zahlen, könnten Sie ein href finden <= "http://www.aspose.com/categories/file-format-components/aspose.network-for-.net /Default.aspx“rel = "nofollow noreferrer"> Aspose.Network nützlich ... es enthält eine iCalendar-kompatible Bibliothek für wiederkehrende Termine.

Sie speichern die Ereignisse im iCalendar-Format direkt, die für offene Wiederholung erlaubt, Zeitzonenlokalisierung und so weiter.

Sie können diese in einem CalDAV-Server zu speichern und dann, wenn Sie die Ereignisse anzeigen möchten, können Sie die Möglichkeit, den Bericht in CalDAV definiert verwenden, um die Server zu bitten, die Erweiterung der wiederkehrenden Ereignisse in dem betrachteten Zeitraum zu tun.

Oder Sie könnten sie in einer Datenbank selbst speichern und eine Art von iCalendar-Parsing-Bibliothek verwenden, um die Erweiterung zu tun, ohne dass die PUT / GET / REPORT zu einem Backend-CalDAV-Server zu sprechen. Dies ist wahrscheinlich mehr Arbeit -. Ich bin sicher, CalDAV-Server Komplexität irgendwo verstecken

die Ereignisse im iCalendar-Format hat, wird wahrscheinlich auf lange Sicht die Dinge einfacher als Menschen immer sie ohnehin in andere Software exportiert werden soll für die Umsetzung.

Ich habe einfach diese Funktion implementiert! Die Logik ist wie folgt, müssen Sie zunächst zwei Tabellen. RuleTable store allgemeine oder väterliche Ereignisse recyceln. ItemTable wird Zyklusereignisse gespeichert. Zum Beispiel, wenn Sie ein zyklisches Ereignis erstellen, um die Startzeit 6. November 2015 die Endzeit für den 6. Dezember (oder für immer), Zyklus für eine Woche. Sie fügen Daten in eine RuleTable, Felder sind wie folgt:

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.

Sie möchten nun 20. November bis 20. Dezember Daten abzufragen. Sie können eine Funktion RecurringEventBE (lange Start, langen Ende) schreiben, bezogen auf die Start- und Endzeit, Wochen-, können Sie die Sammlung berechnen Sie wollen, . Neben 6. November und dem Rest Ich rief ihn ein virtuelles Ereignis. Wenn der Benutzer einen virtuelles Ereignis‘Namen nach (cycleA11.27 zum Beispiel) ändert, fügen Sie ein Datum in eine ItemTable. Die Felder sind wie folgt:

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

In Funktion RecurringEventBE (langen Start, lange Ende), verwenden Sie diese Daten abdeckt virtuelle Veranstaltung (cycleB11.27) traurig über mein Englisch, ich versuchte.

Das ist mein 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); //RuleTable,just 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;
}   
  

Was ist, wenn Sie einen wiederkehrenden Termin ohne Enddatum haben? So billig wie Platz vorhanden ist, müssen Sie nicht den unendlichen Raum, so Lösung 2 ein Rohrkrepierer ist ...

Darf ich vorschlagen, dass „kein Enddatum“ am Ende des Jahrhunderts zu einem Enddatum gelöst werden. Selbst für eine dayly Veranstaltung bleibt die Menge an Speicherplatz billig.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top