Domanda

Sto creando un'applicazione di calendario di gruppo che deve supportare eventi ricorrenti, ma tutte le soluzioni che ho trovato 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 ricorrenti e visualizzarli dinamicamente quando si guarda avanti sul calendario, ma dovrò convertirli in un evento normale se qualcuno vuole modificare i dettagli su una particolare istanza dell'evento.

Sono sicuro che ci sia 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 particolari 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, però, è bene saperlo.)

È stato utile?

Soluzione

Utilizzerei il concetto di "collegamento" per tutti gli eventi ricorrenti futuri.Vengono visualizzati dinamicamente nel calendario e si collegano a un singolo oggetto di riferimento.Quando gli eventi hanno avuto luogo, il collegamento viene interrotto e l'evento diventa un'istanza autonoma.Se tenti di modificare un evento ricorrente, chiedi di modificare tutti gli elementi futuri (ad es.modificare il riferimento collegato singolo) o modificare solo quell'istanza (nel qual caso convertirla in un'istanza autonoma e quindi apportare la modifica).Quest'ultimo caso è leggermente problematico poiché è necessario tenere traccia nell'elenco ricorrente di tutti gli eventi futuri che sono stati convertiti in una singola istanza.Ma questo è del tutto fattibile.

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

Altri suggerimenti

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

Corri gem implementa questo modello.

Possono esserci molti problemi con gli eventi ricorrenti, vorrei evidenziarne alcuni di cui sono a conoscenza.

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 di data quando ne avrai bisogno, il che è costoso
  • Impossibile gestire le eccezioni (es.elimini una delle istanze, o la sposti, o meglio, con questa soluzione non puoi farlo)

Soluzione 2: archivia istanze

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

I problemi:

  • Occupa molto spazio (ma lo spazio è economico, quindi minore)
  • Le eccezioni devono essere gestite con garbo, soprattutto se torni indietro e modifichi l'appuntamento originale dopo aver fatto un'eccezione.Ad esempio, se sposti la terza istanza di un giorno in avanti, cosa succede se torni indietro e modifichi l'orario dell'appuntamento originale, ne reinserisci un altro nel giorno originale e lasci quello spostato?Scollegare quello spostato?Provare a modificare opportunamente quello spostato?

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

Potresti voler esaminare le implementazioni del software iCalendar o lo standard stesso (RFC2445 RFC5545).Quelli che mi vengono in mente subito sono i progetti Mozilla http://www.mozilla.org/projects/calendar/ Una rapida ricerca rivela http://icalendar.rubyforge.org/ anche.

È possibile prendere in considerazione altre opzioni a seconda di come verranno archiviati gli eventi.Stai costruendo il tuo schema di database?Utilizzi qualcosa basato su iCalendar, ecc.?

Sto lavorando con quanto segue:

e un gem in progress che estende formtastic con un input di tipo :recurring (form.schedule :as => :recurring), che rende un'interfaccia simile a iCal e a before_filter per serializzare la vista in un file IceCube obiettare di nuovo, in modo ghetto.

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


Quindi cosa mi dà questo?Attributi indicizzati, modificabili e ricorrenti.

events memorizza un'istanza di un solo giorno e viene utilizzato nella vista/aiutante del calendario task.schedule memorizza lo yaml'd IceCube oggetto, quindi puoi eseguire chiamate come: task.schedule.next_suggestion.

Ricapitolare:Utilizzo due modelli, uno piatto per la visualizzazione del calendario e uno con attributi per la funzionalità.

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 potrebbe essere utile a qualcuno.Sebbene vi siano alcune parti specifiche della libreria che ho scritto, la stragrande maggioranza dei consigli offerti è generale per qualsiasi implementazione del calendario.

Alcuni dei punti chiave:

  • Archiviare la ricorrenza utilizzando il file Formato iCal RRULE - questa è una ruota che davvero non vuoi reinventare
  • NON memorizzare singoli eventi ricorrenti istanze come righe nel tuo database!Archiviare sempre uno schema di ricorrenza.
  • Esistono molti modi per progettare lo schema di eventi/eccezioni, ma viene fornito un esempio di punto di partenza di base
  • Tutti i valori di data/ora devono essere archiviati in UTC e convertiti in locale per la visualizzazione
  • La data di fine memorizzata per un evento ricorrente dovrebbe sempre essere quella data finale dell'intervallo di ricorrenza (o la "data massima" della tua piattaforma se ricorrente "per sempre") e la durata dell'evento devono essere archiviate separatamente.Questo per garantire un modo sensato di interrogare gli eventi in un secondo momento.
  • Sono incluse alcune discussioni sulla generazione di istanze di eventi e sulle strategie di modifica della ricorrenza

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

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

http://github.com/bakineggs/recurring_events_for

Quindi utilizzo runt per calcolare dinamicamente le date.

https://github.com/mlipper/runt

  1. Tieni traccia di una regola di ricorrenza (probabilmente basata su iCalendar, per @Kris K.).Ciò includerà uno schema e un intervallo (ogni terzo martedì, per 10 occorrenze).
  2. Quando desideri modificare/eliminare un evento specifico, tieni traccia delle date di eccezione per la regola di ricorrenza di cui sopra (date in cui l'evento no verificarsi come specificato dalla regola).
  3. Se hai eliminato, è tutto ciò di cui hai bisogno, se hai 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 conservare solo le modifiche ed ereditare tutto ciò che non cambia.

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

Spero che aiuti!

Consiglierei di utilizzare la potenza della libreria di date e la semantica del modulo range di Ruby.Un evento ricorrente è in realtà un'ora, un intervallo di date (inizio e fine) e solitamente un singolo giorno della settimana.Utilizzando 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, Compreso 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\"]"

Da queste risposte, ho in qualche modo vagliato 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.Cambiare un evento sarebbe quindi facile, perché i collegamenti rimangono al loro posto, e anche eliminare un evento è facile: basta scollegare un evento, eliminarlo e ricollegare l'evento prima e dopo.Devi ancora interrogare gli eventi ricorrenti ogni volta che qualcuno guarda un nuovo periodo di tempo mai visto prima sul calendario, ma per il resto è abbastanza pulito.

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

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

In Javascript:

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

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

Fondamentalmente, crei le regole quindi 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 hai un evento ricorrente e desideri modificare solo una ricorrenza puoi utilizzare il file tranne() funzione per eliminare un giorno particolare e quindi aggiungere un nuovo evento modificato per questa voce.

La libreria supporta modelli molto complessi, fusi orari e persino eventi di croning.

Memorizza gli eventi come ricorrenti 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 interroghi l'evento ricorrente, puoi verificare la presenza di una sostituzione specifica per quel giorno.

Se un utente apporta modifiche, puoi chiedergli se desidera aggiornare per tutte le istanze (dettagli predefiniti) o solo per quel giorno (creare un nuovo evento specifico e aggiungerlo 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 volesse aggiornare questo evento e tutti gli eventi futuri.In tal caso dovrai dividere l'evento ricorrente in due.A questo punto potresti prendere in considerazione la possibilità di collegare in qualche modo gli eventi ricorrenti in modo da poterli eliminare tutti.

Per i programmatori .NET disposti a pagare alcuni costi di licenza, potresti trovare Aspose.Network utile...include una libreria compatibile con iCalendar per appuntamenti ricorrenti.

Memorizzi gli eventi direttamente nel formato iCalendar, che consente la ripetizione illimitata, la localizzazione del fuso orario e così via.

È possibile memorizzarli in un server CalDAV e poi, 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 potresti memorizzarli tu stesso in un database e utilizzare una sorta di libreria di analisi iCalendar per eseguire l'espansione, senza bisogno che PUT/GET/REPORT comunichi con un server CalDAV backend.Questo probabilmente richiede più lavoro: sono sicuro che i server CalDAV nascondono la 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 esportati per inserirli comunque in altri software.

Ho semplicemente implementato questa funzionalità!La logica è la seguente, prima hai bisogno di due tabelle.RuleTable memorizza eventi generali o ricicla gli eventi paterni.ItemTable contiene eventi di ciclo memorizzati.Ad esempio, quando crei un evento ciclico, l'ora di inizio per il 6 novembre 2015, l'ora di fine per il 6 dicembre (o per sempre), ciclica per una settimana.Si inseriscono 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 eseguire una query sui dati dal 20 novembre al 20 dicembre.Puoi scrivere una funzione RecurringEventBE (long start, long end), in base all'ora di inizio e fine, WeekLy, puoi calcolare la raccolta desiderata, < cycleA11.20, cycleA 11.27, cycleA 12.4 ......>.Oltre al 6 novembre e al resto l'ho definito un evento virtuale.Quando l'utente modifica il nome di un evento virtuale dopo (ad esempio cycleA11.27), inserisci 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 ricorrenteEventBe (lungo inizio, end long), si utilizzano questi dati che coprono evento virtuale (CycleB11.27) scusa per il mio inglese, ho provato.

Questo è il mio evento ricorrenteBE:

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

Cosa succede se hai un appuntamento ricorrente senza data di fine?Per quanto economico sia lo spazio, non hai spazio infinito, quindi la Soluzione 2 non è un punto di partenza lì...

Posso suggerire che la "nessuna data finale" può essere risolta con una data finale alla fine del secolo.Anche per un evento quotidiano la quantità di spazio rimane economica.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top