it-swarm.it

Qual è il modo migliore per modellare eventi ricorrenti in un'applicazione di calendario?

Sto creando un'applicazione di calendario di gruppo che deve supportare eventi ricorrenti, ma tutte le soluzioni che ho ideato per gestire questi eventi sembrano un trucco. Posso limitare quanto lontano si può guardare e quindi generare tutti gli eventi contemporaneamente. Oppure posso memorizzare gli eventi come ripetuti e visualizzarli dinamicamente quando uno guarda avanti nel calendario, ma dovrò convertirli in un evento normale se qualcuno vuole cambiare i dettagli su una particolare istanza dell'evento.

Sono sicuro che c'è un modo migliore per farlo, ma non l'ho ancora trovato. Qual è il modo migliore per modellare eventi ricorrenti, in cui è possibile modificare i dettagli o eliminare determinate istanze di eventi?

(Sto usando Ruby, ma per favore non lasciare che questo limiti la tua risposta. Se c'è una libreria specifica per Ruby o qualcosa del genere, è bene saperlo.)

213

Vorrei utilizzare un concetto di "collegamento" per tutti i futuri eventi ricorrenti. Sono visualizzati dinamicamente nel calendario e rimandano a un singolo oggetto di riferimento. Quando si verificano eventi, il collegamento viene interrotto e l'evento diventa un'istanza autonoma. Se tenti di modificare un evento ricorrente, quindi Richiedi di cambiare tutti gli elementi futuri (ovvero cambia singolo riferimento collegato) o cambia solo quell'istanza (nel qual caso converti questo in un'istanza autonoma e poi apporta la modifica). Quest'ultimo caso è leggermente problematico in quanto è necessario tenere traccia dell'elenco ricorrente di tutti gli eventi futuri che sono stati convertiti in singola istanza. Ma questo è del tutto fattibile.

Quindi, in sostanza, hanno 2 classi di eventi: singole istanze ed eventi ricorrenti.

84
user16068

Martin Fowler - Eventi ricorrenti per calendari contiene alcuni spunti e schemi interessanti.

Runt gem implementa questo modello.

54
Daniel Maurić

Ci possono essere molti problemi con eventi ricorrenti, fammi evidenziare alcuni che conosco.

Soluzione 1 - nessuna istanza

Memorizza appuntamento originale + dati di ricorrenza, non memorizzare tutte le istanze.

I problemi:

  • Dovrai calcolare tutte le istanze in una finestra della data quando ne avrai bisogno, costose
  • Impossibile gestire le eccezioni (ad es. Eliminare una delle istanze o spostarla, o meglio, non è possibile farlo con questa soluzione)

Soluzione 2: memorizzare le istanze

Memorizza tutto da 1, ma anche tutte le istanze, ricollegate all'appuntamento originale.

I problemi:

  • Occupa molto spazio (ma lo spazio è economico, quindi minore)
  • Le eccezioni devono essere gestite con garbo, specialmente se torni indietro e modifichi l'appuntamento originale dopo aver fatto un'eccezione. Ad esempio, se si sposta in avanti la terza istanza di un giorno, cosa succede se si torna indietro e si modifica l'ora dell'appuntamento originale, si inserisce un altro giorno originale e si lascia quello spostato? Scollegare quello spostato? Cerchi di cambiare quello spostato in modo appropriato?

Naturalmente, se non hai intenzione di fare eccezioni, allora entrambe le soluzioni dovrebbero andare bene e fondamentalmente scegli uno scenario di trade-time/spazio.

Potresti voler esaminare le implementazioni del software iCalendar o lo standard stesso (RFC 2445 RFC 5545 ). A venire subito in mente sono i progetti Mozilla http://www.mozilla.org/projects/calendar/ Una rapida ricerca rivela http://icalendar.rubyforge.org/ pure.

Altre opzioni possono essere considerate in base al modo in cui memorizzerai gli eventi. Stai creando il tuo schema di database? Usi qualcosa basato su iCalendar, ecc.?

17
Kris Kumler

Sto lavorando con il seguente:

e una gemma in corso che estende formtastic con un tipo di input: ricorrente (form.schedule :as => :recurring), che esegue il rendering di un'interfaccia simile a iCal e di un before_filter per serializzare nuovamente la vista in un oggetto IceCube, ghetto-ly.

La mia idea è rendere incredibilmente facile l'aggiunta di attributi ricorrenti a un modello e collegarlo facilmente nella vista. Tutto in un paio di righe.


Cosa mi dà questo? Attributi indicizzati, modificabili, ricorrenti.

events memorizza un'istanza di un solo giorno e viene utilizzata nella vista del calendario/helper say task.schedule memorizza l'oggetto IceCube yaml'd, in modo da poter effettuare chiamate come: task.schedule.next_suggestion.

Riepilogo: utilizzo due modelli, uno piatto, per la visualizzazione del calendario e uno attribuito per la funzionalità.

16
Vee

Ho sviluppato più applicazioni basate su calendario e ho anche creato una serie di componenti di calendario JavaScript riutilizzabili che supportano la ricorrenza. Ho scritto una panoramica di come progettare per la ricorrenza che potrebbe essere utile a qualcuno. Mentre ci sono alcuni bit specifici della libreria che ho scritto, la stragrande maggioranza dei consigli offerti è generale per qualsiasi implementazione del calendario.

Alcuni dei punti chiave:

  • Memorizza la ricorrenza usando il formato iCal RRULE - questa è una ruota che non vuoi davvero reinventare
  • NON memorizzare singole istanze di eventi ricorrenti come righe nel tuo database! Memorizza sempre un modello di ricorrenza.
  • Esistono molti modi per progettare lo schema di eventi/eccezioni, ma viene fornito un esempio di base di partenza
  • Tutti i valori di data/ora devono essere memorizzati in UTC e convertiti in locali per la visualizzazione
  • La data di fine memorizzata per un evento ricorrente dovrebbe essere sempre la data di fine dell'intervallo di ricorrenza (o la "data massima" della piattaforma se ricorrente "per sempre") e la durata dell'evento deve essere memorizzata separatamente. Questo per garantire un modo sano di interrogare gli eventi in un secondo momento.
  • Sono incluse alcune discussioni sulla generazione di istanze di eventi e sulle strategie di modifica delle ricorrenze

È un argomento davvero complicato con molti, molti approcci validi per implementarlo. Dirò che ho effettivamente implementato la ricorrenza più volte con successo, e sarei diffidente nel prendere consigli su questo argomento da chiunque non l'abbia effettivamente fatto.

14
Brian Moeskau

Sto usando lo schema del database come descritto di seguito per memorizzare i parametri di ricorrenza

http://github.com/bakineggs/recurring_events_for

Quindi uso Runt per calcolare dinamicamente le date.

https://github.com/mlipper/runt

6
liangzan
  1. Tieni traccia di una regola di ricorrenza (probabilmente basata su iCalendar, per @ Kris K. ). Ciò includerà un modello e un intervallo (ogni terzo martedì, per 10 occorrenze).
  2. Per quando si desidera modificare/eliminare un'occorrenza specifica, tenere traccia delle date di eccezione per la regola di ricorrenza sopra (date in cui l'evento non si verifica come la regola specifica).
  3. Se hai eliminato, è tutto ciò che ti serve, se modificato, crea un altro evento e assegnagli un ID genitore impostato sull'evento principale. Puoi scegliere se includere tutte le informazioni dell'evento principale in questo record o se contiene solo le modifiche ed eredita tutto ciò che non cambia.

Nota che se consenti regole di ricorrenza che non finiscono, devi pensare a come visualizzare la tua quantità infinita di informazioni.

Spero che sia d'aiuto!

5
bdukes

Consiglio di utilizzare la potenza della libreria di date e la semantica del modulo di intervallo di Ruby. Un evento ricorrente è davvero un orario, un intervallo di date (un inizio e una fine) e di solito un solo giorno della settimana. Usando data e intervallo puoi rispondere a qualsiasi domanda:

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

Produce tutti i giorni dell'evento, incluso l'anno bisestile!

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

Da queste risposte ho setacciato una soluzione. Mi piace molto l'idea del concetto di collegamento. Gli eventi ricorrenti potrebbero essere un elenco collegato, con la coda che conosce la sua regola di ricorrenza. La modifica di un evento sarebbe quindi facile, poiché i collegamenti rimangono attivi e anche l'eliminazione di un evento è semplice: basta scollegare un evento, eliminarlo e ricollegare l'evento prima e dopo di esso. Devi ancora interrogare gli eventi ricorrenti ogni volta che qualcuno guarda un nuovo periodo di tempo mai visto prima nel calendario, ma per il resto questo è abbastanza pulito.

3

Controlla l'articolo qui sotto per tre buoni Ruby librerie di data/ora. Ice_cube in particolare sembra una solida scelta per le regole di ricorrenza e altre cose che un calendario di eventi avrebbe bisogno. http: // www.rubyinside.com/3-new-date-and-time-libraries-for-rubyists-3238.html

2
gokul.janga

È possibile archiviare gli eventi come ripetuti e, se una particolare istanza è stata modificata, creare un nuovo evento con lo stesso ID evento. Quindi, quando si cerca l'evento, cercare tutti gli eventi con lo stesso ID evento per ottenere tutte le informazioni. Non sono sicuro se hai creato la tua libreria eventi o se ne stai utilizzando una esistente, quindi potrebbe non essere possibile.

2
Vincent McNabb

In javascript:

Gestione delle pianificazioni ricorrenti: http://bunkat.github.io/later/

Gestione di eventi complessi e dipendenze tra tali programmi: http://bunkat.github.io/schedule/

Fondamentalmente, crei le regole e poi chiedi alla lib di calcolare i successivi N eventi ricorrenti (specificando o meno un intervallo di date). Le regole possono essere analizzate/serializzate per salvarle nel modello.

Se si dispone di un evento ricorrente e si desidera modificare solo una ricorrenza, è possibile utilizzare la funzione tranne () per chiudere un determinato giorno e quindi aggiungere un nuovo evento modificato per questa voce.

La libreria supporta schemi, fusi orari e persino cronologia molto complessi.

1
Flavien Volken

Per i programmatori .NET che sono pronti a pagare alcune tasse di licenza, potresti trovare Aspose.Network utile ... include una libreria compatibile iCalendar per appuntamenti ricorrenti.

0
Shaul Behr

Archivia gli eventi come ripetuti e visualizzali dinamicamente, tuttavia consenti all'evento ricorrente di contenere un elenco di eventi specifici che potrebbero sovrascrivere le informazioni predefinite in un giorno specifico.

Quando si esegue una query sull'evento ricorrente, è possibile verificare una specifica sostituzione per quel giorno.

Se un utente apporta modifiche, puoi chiedere se desidera eseguire l'aggiornamento per tutte le istanze (dettagli predefiniti) o solo quel giorno (crea un nuovo evento specifico e aggiungilo all'elenco).

Se un utente chiede di eliminare tutte le ricorrenze di questo evento, hai anche l'elenco delle specifiche a portata di mano e puoi rimuoverle facilmente.

L'unico caso problematico sarebbe se l'utente desidera aggiornare questo evento e tutti gli eventi futuri. Nel qual caso dovrai dividere l'evento ricorrente in due. A questo punto potresti prendere in considerazione l'idea di collegare gli eventi ricorrenti in qualche modo in modo da poterli eliminare tutti.

0
Andrew Johnson

Memorizzi direttamente gli eventi in formato iCalendar, il che consente la ripetizione a tempo indeterminato, la localizzazione del fuso orario e così via.

È possibile archiviarli in un server CalDAV e quindi, quando si desidera visualizzare gli eventi, è possibile utilizzare l'opzione del report definito in CalDAV per chiedere al server di eseguire l'espansione degli eventi ricorrenti nel periodo visualizzato.

Oppure puoi archiviarli in un database da solo e utilizzare una sorta di libreria di analisi iCalendar per eseguire l'espansione, senza bisogno di PUT/GET/REPORT per parlare con un server CalDAV back-end. Questo è probabilmente più lavoro - sono sicuro che i server CalDAV nascondono complessità da qualche parte.

Avere gli eventi in formato iCalendar probabilmente renderà le cose più semplici a lungo termine poiché le persone vorranno sempre che vengano esportate per mettere comunque in altro software.

0
karora

Ho semplicemente implementato questa funzione! La logica è la seguente, prima sono necessarie due tabelle. Regola Tabella memorizza eventi generali o di riciclo. ItemTable è gli eventi del ciclo memorizzati. Ad esempio, quando si crea un evento ciclico, l'ora di inizio per il 6 novembre 2015, l'ora di fine per il 6 dicembre (o per sempre), scorrono per una settimana. Inserisci i dati in una RuleTable, i campi sono i seguenti:

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.

Ora vuoi interrogare i dati dal 20 novembre al 20 dicembre. È possibile scrivere una funzione RecurringEventBE (inizio lungo, fine lungo), in base all'ora di inizio e di fine, WeekLy, è possibile calcolare la raccolta desiderata, <ciclo A11.20, ciclo A 11,27, ciclo A 12,4 ......>. Oltre al 6 novembre e al resto, l'ho chiamato un evento virtuale. Quando l'utente cambia il nome di un evento virtuale dopo (ad esempio cycleA11.27), si inseriscono i dati in una ItemTable. I campi sono i seguenti:

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

Nella funzione RecurringEventBE (inizio lungo, fine lungo), usi questi dati relativi all'evento virtuale (ciclo B11.27) scusami per il mio inglese, ho provato.

Questo è il mio Evento ricorrente ing

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;
}   
0
fozua