Quel est le meilleur moyen de modéliser des événements récurrents dans une application de calendrier?

StackOverflow https://stackoverflow.com/questions/85699

Question

Je construis une application d'agenda de groupe qui doit prendre en charge les événements récurrents, mais toutes les solutions que j'ai proposées pour gérer ces événements semblent être un hack. Je peux limiter l’avenir, puis générer tous les événements en même temps. Ou je peux stocker les événements comme étant répétés et les afficher dynamiquement quand on regarde l'avenir, mais je devrai les convertir en un événement normal si quelqu'un veut changer les détails d'une instance particulière de l'événement.

Je suis sûr qu'il existe un meilleur moyen de faire cela, mais je ne l'ai pas encore trouvé. Quelle est la meilleure façon de modéliser des événements récurrents, où vous pouvez modifier les détails ou supprimer des instances d’événement particulières?

(J'utilise Ruby, mais s'il vous plaît, ne laissez pas cela contraindre votre réponse. S'il existe une bibliothèque spécifique à Ruby ou quelque chose d'autre, c'est bon à savoir.)

Était-ce utile?

La solution

J'utiliserais un concept de "lien" pour tous les événements récurrents à venir. Ils sont affichés dynamiquement dans le calendrier et sont liés à un seul objet de référence. Lorsque des événements ont eu lieu, le lien est rompu et l'événement devient une instance autonome. Si vous essayez de modifier un événement récurrent, demandez à modifier tous les éléments à venir (par exemple, changer une référence liée unique) ou à changer cette instance uniquement (dans ce cas, convertissez-le en une instance autonome, puis apportez des modifications). Ce dernier cas est légèrement problématique car vous devez garder une trace dans votre liste récurrente de tous les événements futurs convertis en instance unique. Mais c’est tout à fait faisable.

Donc, vous avez essentiellement 2 classes d’événements - des instances uniques et des événements récurrents.

Autres conseils

Martin Fowler - Evénements récurrents pour les calendriers contient des informations et des modèles intéressants.

Runt gem implémente ce modèle.

Il peut y avoir beaucoup de problèmes avec les événements récurrents, laissez-moi en souligner quelques-uns que je connaisse.

Solution 1 - Aucune instance

Stockez les données de rendez-vous d'origine + récurrence, ne stockez pas toutes les instances.

Problèmes:

  • Vous devrez calculer toutes les instances dans une fenêtre de date lorsque vous en aurez besoin, ce qui est coûteux
  • Impossible de gérer les exceptions (vous supprimez ou déplacez l'une des instances ou vous ne pouvez pas le faire avec cette solution)

Solution 2 - Stockez les instances

Stockez tout à partir de 1, mais aussi toutes les instances, liées au rendez-vous d'origine.

Problèmes:

  • prend beaucoup d'espace (mais l'espace est peu coûteux, donc mineur)
  • Les exceptions doivent être gérées avec élégance, en particulier si vous revenez en arrière et modifiez le rendez-vous d'origine après avoir créé une exception. Par exemple, si vous avancez d'un jour la troisième instance, si vous revenez en arrière et modifiez l'heure du rendez-vous d'origine, réinsérez-en une autre le jour d'origine et laissez celle déplacée. Dissocier le déplacé? Essayez de changer le déplacé de manière appropriée?

Bien sûr, si vous ne faites pas d’exceptions, alors l’une ou l’autre des solutions devrait convenir, et vous optez pour un scénario de compensation temps / espace.

Vous voudrez peut-être regarder les implémentations logicielles iCalendar ou la norme elle-même ( RFC 2445 RFC 5545 ). Les projets Mozilla à retenir rapidement sont http://www.mozilla.org/projects/calendar/ Une recherche rapide indique également http://icalendar.rubyforge.org/ .

D'autres options peuvent être envisagées en fonction de la manière dont vous allez stocker les événements. Construisez-vous votre propre schéma de base de données? Utiliser quelque chose basé sur iCalendar, etc.?

Je travaille avec les éléments suivants:

et un joyau en cours qui étend formtastic avec un type d'entrée: récurrent (form.schedule :as => :recurring), qui restitue une interface de type iCal et un before_filter pour sérialiser de nouveau la vue dans un objet IceCube, de manière ghetto-ly .

Mon idée est de faciliter l’incrédibilité en ajoutant des attributs récurrents à un modèle et en le connectant facilement dans la vue. Tout en quelques lignes.

Alors qu'est-ce que cela me donne? Attributs indexés, modifiables, récurrents.

events stocke une instance unique, et est utilisé dans la vue de calendrier / l'aide dites task.schedule enregistre l'objet yaml'd task.schedule.next_suggestion afin que vous puissiez effectuer des appels tels que: <=>.

Récapitulation: j’utilise deux modèles, un à plat pour l’affichage du calendrier et un attribut pour la fonctionnalité.

J'ai développé plusieurs applications basées sur un calendrier et créé un ensemble de composants de calendrier JavaScript réutilisables prenant en charge la périodicité. J'ai rédigé un aperçu de la comment créer une récurrence qui pourrait être utile à quelqu'un. Bien que certains éléments soient spécifiques à la bibliothèque que j'ai écrite, la grande majorité des conseils offerts sont généraux pour toute implémentation de calendrier.

Quelques points clés:

  • Mémorisez la récurrence en utilisant le format RRULE iCal . ne veulent pas réinventer
  • Ne stockez PAS les instances d'événements récurrents individuelles en tant que lignes dans votre base de données! Toujours stocker un modèle de récurrence.
  • Il existe de nombreuses façons de concevoir votre schéma d'événement / exception, mais un exemple de base de départ est fourni
  • Toutes les valeurs de date / heure doivent être stockées en UTC et converties en locales pour l'affichage
  • La date de fin stockée pour un événement récurrent doit toujours être la date de fin de la plage de récurrence (ou la " max date & de votre plate-forme & "si récurrent &" ; forever ") et la durée de l’événement doit être stockée séparément. Ceci afin de garantir un moyen sain d’interroger les événements ultérieurement.
  • Des discussions sur la génération d'instances d'événement et de stratégies d'édition de récurrence sont incluses

C’est un sujet très compliqué qui comporte de nombreuses approches valables pour l’appliquer. Je dirai que j’ai effectivement mis en œuvre la récurrence à plusieurs reprises avec succès et que je me garderais de prendre conseil à ce sujet de la part de ceux qui ne l’ont pas réellement fait.

J'utilise le schéma de base de données décrit ci-dessous pour stocker les paramètres de récurrence

http://github.com/bakineggs/recurring_events_for

Ensuite, j'utilise runt pour calculer dynamiquement les dates.

https://github.com/mlipper/runt

  1. Gardez une trace d'une règle de récurrence (probablement basée sur iCalendar, comme indiqué par @ Kris K. ). Cela inclura un motif et une plage (chaque mardi sur trois, pour 10 occurrences).
  2. Lorsque vous souhaitez modifier / supprimer une occurrence spécifique, gardez une trace des dates d'exception pour la règle de récurrence ci-dessus (dates où l'événement ne se produit pas comme le spécifie la règle).
  3. Si vous avez supprimé, c'est tout ce dont vous avez besoin. Si vous avez édité, créez un autre événement et attribuez-lui un ID parent défini pour l'événement principal. Vous pouvez choisir d'inclure toutes les informations de l'événement principal dans cet enregistrement ou s'il ne conserve que les modifications et hérite de tout ce qui ne change pas.

Notez que si vous autorisez les règles de récurrence qui ne se terminent pas, vous devez réfléchir à la façon d'afficher votre quantité d'informations désormais infinie.

J'espère que ça aide!

Je vous conseillerais d'utiliser la puissance de la bibliothèque de dates et la sémantique du module range de ruby. Un événement récurrent est en réalité une heure, une plage de dates (un début & Et une fin) et généralement un seul jour de la semaine. Utilisation de la date & Amp; vous pouvez répondre à n’importe quelle question:

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

Produit tous les jours de l'événement, y compris l'année bissextile!

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

À partir de ces réponses, j'ai en quelque sorte trouvé une solution. J'aime beaucoup l'idée du concept de lien. Les événements récurrents peuvent être une liste chaînée, la queue connaissant sa règle de récurrence. Changer un événement serait alors facile, car les liens restent en place et la suppression d'un événement est également facile: vous dissociez simplement un événement, supprimez-le et reliez-le avant et après. Vous devez toujours interroger les événements récurrents chaque fois que quelqu'un regarde une nouvelle période de temps jamais vue auparavant dans le calendrier, mais sinon, c'est assez propre.

Vous pouvez stocker les événements comme étant répétés et, si une instance particulière a été modifiée, créer un nouvel événement avec le même ID d'événement. Ensuite, lors de la recherche de l'événement, recherchez tous les événements avec le même ID d'événement pour obtenir toutes les informations. Je ne sais pas si vous avez lancé votre propre bibliothèque d’événements ou si vous en utilisez une existante, ce n’est peut-être pas possible.

Consultez l’article ci-dessous pour consulter trois bonnes bibliothèques de date / heure de ruby. ice_cube en particulier semble être un choix judicieux pour les règles de récurrence et autres éléments nécessaires à un calendrier d'événements. http://www.rubyinside.com /3-new-date-and-time-libraries-for-rubyists-3238.html

En javascript:

Gestion des horaires récurrents: http://bunkat.github.io/later/

Gestion des événements complexes et des dépendances entre ces horaires: http://bunkat.github.io/schedule/

En gros, vous créez les règles, puis vous demandez à la bibliothèque de calculer les N prochains événements récurrents (en spécifiant une plage de dates ou non). Les règles peuvent être analysées / sérialisées pour les enregistrer dans votre modèle.

Si vous avez un événement récurrent et souhaitez modifier une seule récurrence, vous pouvez utiliser la fonction except () pour ignorer un jour particulier, puis ajouter un nouvel événement modifié pour cette entrée. .

La bibliothèque prend en charge des modèles, des fuseaux horaires et même des événements complexes très complexes.

Stockez les événements de manière répétée et affichez-les de manière dynamique, mais autorisez l’événement récurrent à contenir une liste d’événements spécifiques susceptibles de remplacer les informations par défaut un jour donné.

Lorsque vous interrogez l'événement récurrent, il peut rechercher un remplacement spécifique pour ce jour-là.

Si un utilisateur apporte des modifications, vous pouvez lui demander s'il souhaite mettre à jour pour toutes les instances (détails par défaut) ou juste pour ce jour-là (créer un nouvel événement spécifique et l'ajouter à la liste).

Si un utilisateur vous demande de supprimer toutes les récurrences de cet événement, vous disposez également de la liste des détails et pouvez les supprimer facilement.

Le seul problème serait que l'utilisateur souhaite mettre à jour cet événement et tous les événements futurs. Dans ce cas, vous devrez scinder l'événement récurrent en deux. À ce stade, vous pouvez envisager de lier d’une manière ou d’une autre les événements récurrents afin de pouvoir les supprimer tous.

Pour les programmeurs .NET prêts à payer des frais de licence, vous pouvez trouver Aspose.Network utile ... il inclut une bibliothèque compatible iCalendar pour les rendez-vous périodiques.

Vous stockez les événements au format iCalendar directement, ce qui permet la répétition à durée indéterminée, la localisation du fuseau horaire, etc.

.

Vous pouvez les stocker sur un serveur CalDAV, puis, lorsque vous souhaitez afficher les événements, vous pouvez utiliser l'option du rapport défini dans CalDAV pour demander au serveur de développer les événements récurrents sur la période visualisée.

Vous pouvez également les stocker vous-même dans une base de données et utiliser une sorte de bibliothèque d’analyses iCalendar pour procéder à l’extension, sans avoir besoin de PUT / GET / REPORT pour communiquer avec un serveur CalDAV principal. C’est probablement plus de travail - je suis sûr que les serveurs CalDAV cachent la complexité quelque part.

Le fait d’avoir les événements au format iCalendar simplifiera probablement les choses à long terme, car les utilisateurs voudront toujours qu’ils soient exportés pour pouvoir intégrer d’autres logiciels.

J'ai simplement implémenté cette fonctionnalité! La logique est la suivante, vous avez d’abord besoin de deux tables. RuleTable stocke des événements généraux ou recycle. ItemTable est des événements de cycle stockés. Par exemple, lorsque vous créez un événement cyclique, l'heure de début du 6 novembre 2015, l'heure de fin du 6 décembre (ou indéfiniment), se répète pendant une semaine. Vous insérez des données dans un RuleTable, les champs sont les suivants:

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.

Vous souhaitez maintenant interroger les données du 20 novembre au 20 décembre. Vous pouvez écrire une fonction RecurringEventBE (début long, bout long), en fonction de l'heure de début et de fin, Weekly, vous pouvez calculer la collection souhaitée, & Lt; cycleA11.20, cycle A 11.27, cycle A 12.4 ...... > ;. En plus du 6 novembre et du reste, je l'ai qualifié d'événement virtuel. Lorsque l'utilisateur modifie un nom d'événement virtuel après (cycleA11.27 par exemple), vous insérez une donnée dans un élément ItemTable. Les champs sont les suivants:

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

Dans la fonction RecurringEventBE (début long, bout long), vous utilisez ces données couvrant l'événement virtuel (cycle B11.27). désolé pour mon anglais, j'ai essayé.

Ceci est mon Evénement récurrent & # 65306;

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

Et si vous avez un rendez-vous récurrent sans date de fin? Aussi bon marché que soit l’espace, vous n’avez pas d’espace infini, donc Solution 2 est un non-démarreur ...

Puis-je suggérer que & "pas de date de fin &"; peuvent être résolus jusqu’à la fin du siècle. Même pour un événement quotidien, l'espace disponible reste bon marché.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top