Pergunta

Estou construindo uma aplicação de calendário de grupo que as necessidades para apoiar eventos recorrentes, mas todas as soluções que eu vim acima com para lidar com esses eventos parece ser um hack. Eu posso limitar o quão longe à frente pode-se olhar, e em seguida, gerar todos os eventos de uma só vez. Ou posso armazenar os eventos como a repetição e dinamicamente exibi-los Quando se olha em frente no calendário, mas eu vou ter que convertê-los para um evento normal, se alguém quer mudar os detalhes de uma instância específica do evento.

Eu tenho certeza que há uma maneira melhor de fazer isso, mas eu não tê-lo encontrado ainda. Qual é a melhor maneira de modelo de eventos, onde você pode alterar os detalhes ou excluir instâncias especial de eventos recorrentes?

(estou usando Ruby, mas por favor não deixe que restringem a sua resposta. Se há uma biblioteca específica em Ruby ou algo, porém, que é bom saber.)

Foi útil?

Solução

Gostaria de usar um conceito 'link' para todos os futuros eventos recorrentes. Eles são exibidos de forma dinâmica no calendário e link de volta para um único objeto de referência. Quando os eventos ter ocorrido a ligação é interrompida e o evento se torna uma instância independente. Se você tentar editar um evento recorrente em seguida, solicitação para alterar todos os itens futuros (ou seja, a mudança de referência único ligado) ou mude apenas essa instância (caso em que converter isso em uma instância independente e, em seguida, fazer a mudança). O último Cased é um pouco problemático como você precisa manter o controle em sua lista recorrente de todos os eventos futuros que foram convertidas para única instância. Mas, isso é totalmente capaz de fazer.

Então, em essência, tem 2 classes de eventos -. Exemplos individuais e eventos recorrentes

Outras dicas

Martin Fowler -. Recorrentes Eventos para Calendários contém algumas idéias e padrões interessantes

Runt gem implementa este padrão.

Pode haver muitos problemas com eventos recorrentes, deixe-me destacar alguns que eu conheço.

Solução 1 - há casos

Armazenar dados compromisso original + recorrência, não armazene todas as instâncias.

Problemas:

  • Você vai ter que calcular todas as instâncias em uma janela de data quando você precisa deles, caro
  • Não é possível para exceções identificador (isto é. Você excluir um dos casos, ou movê-lo, ou melhor, você não pode fazer isso com esta solução)

Solução 2 - casos de loja

loja tudo a partir de 1, mas também todos os casos, de volta ligada ao compromisso original.

Problemas:

  • tem um monte de espaço (mas o espaço é barato, por isso menor)
  • As exceções devem ser tratadas com graça, especialmente se você voltar e editar o compromisso original depois de fazer uma exceção. Por exemplo, se você mover a terceira instância de um dia em diante, o que se você voltar e editar o tempo da nomeação original, re-inserir outro no dia original e deixar a se moveu? Desvincular a se moveu? Tente mudar o moveu uma forma adequada?

Claro que, se você não vai fazer exceções, então qualquer solução deve estar bem, e você basicamente escolher um comércio tempo / espaço off cenário.

Você pode querer olhar para implementações de software iCalendar ou o próprio padrão ( RFC 2445 RFC 5545 ). Ones to vêm à mente rapidamente são os projetos Mozilla http://www.mozilla.org/projects/calendar/ Uma rápida pesquisa revela http://icalendar.rubyforge.org/ também.

Outras opções podem ser considerados dependendo de como você está indo para armazenar os eventos. Você está construindo o seu próprio esquema de banco de dados? Usando algo baseado em iCalendar, etc.?

Eu estou trabalhando com o seguinte:

e uma gema em curso que se estende Formtastic com um tipo de entrada:. Recorrentes (form.schedule :as => :recurring), o que torna um iCal interface semelhante e um before_filter serializar a vista em um objeto IceCube novamente, gueto-ly

A minha ideia é torná-lo incredibilidade fácil adicionar atributos para um modelo recorrente e conectá-lo facilmente na exibição. Tudo em um par de linhas.


Assim que isto me dar? Indexada, Edit-capazes, recorrentes atributos.

events lojas de uma única instância dia, e é usado na exibição de calendário / helper dizem lojas task.schedule o objeto yaml'd IceCube, para que possa fazer chamadas como:. task.schedule.next_suggestion

Recap: Eu uso dois modelos, um plano, para a exibição de calendário, e um attribute'd para a funcionalidade

.

Eu desenvolvi vários aplicativos baseados no calendário, e também autor de um conjunto de componentes de calendário de JavaScript reutilizáveis ??que suportam recorrência. Eu escrevi uma visão geral como projetar para a recorrência que o poder ser útil a alguém. Embora existam alguns pedaços que são específicos para a biblioteca que eu escrevi, a grande maioria do conselho oferecido é geral para qualquer aplicação de calendário.

Alguns dos pontos-chave:

  • recorrência loja usando o iCal RRULE formato - que é uma roda que você realmente não quero reinventar
  • Não guarde evento recorrente indivíduo casos como linhas na sua base de dados! Sempre armazenar um padrão de recorrência.
  • Existem muitas maneiras de conceber o seu esquema de eventos / exceção, mas um exemplo básico ponto de partida é fornecido
  • Todos os valores de data / hora devem ser armazenados em UTC e convertido ao local para exibição
  • A data final armazenado durante um evento recorrente deve ser sempre o data final do intervalo de recorrência (ou "data max" de sua plataforma se recorrentes "para sempre") e a duração do evento devem ser armazenados separadamente . Isso é para garantir uma maneira sã de consulta para eventos mais tarde.
  • Alguns discussão em torno gerando casos de eventos e editar estratégias de recorrência está incluído

É um tema muito complicado com muitas, muitas abordagens válidas para sua implementação. Posso dizer que eu realmente implementado recorrência várias vezes com sucesso, e eu seria cauteloso em tomar conselhos sobre este assunto a partir de alguém que não tenha realmente feito isso.

Eu estou usando o esquema de banco de dados, conforme descrito abaixo para armazenar os parâmetros de recorrência

http://github.com/bakineggs/recurring_events_for

Então eu uso nanico para dinamicamente calcular as datas.

https://github.com/mlipper/runt

  1. faixa de manter uma regra de recorrência (provavelmente baseado em iCalendar, por @ Kris K. ). Isso irá incluir um padrão e uma gama (cada terceira terça-feira, por 10 ocorrências).
  2. Para quando você quer editar / excluir uma ocorrência específica, manter o controle de datas de exceção para a regra acima recorrência (datas em que o evento não ocorrer como especifica a regra).
  3. Se você excluiu, isso é tudo que você precisa, se você editou, criar um outro evento, e dar-lhe um conjunto ID pai para o evento principal. Você pode escolher se deseja incluir todas as informações principal do evento neste registro, ou se ele apenas detém as mudanças e herda tudo o que não muda.

Note que se você permitir que as regras de recorrência que não terminam, você tem que pensar sobre como mostrar o seu valor agora infinita de informação.

Espero que ajude!

Eu recomendo usar o poder da biblioteca data e a semântica do módulo gama de rubi. Um evento recorrente é realmente um tempo, um intervalo de datas (um começo e fim) e, geralmente, um único dia da semana. Com data e a distância a que pode responder a qualquer pergunta:

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

Produz todos os dias do evento, incluindo o ano bissexto!

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

A partir dessas respostas, eu tenho tipo de peneirada uma solução. Eu realmente gosto da idéia do conceito link. eventos recorrentes poderia ser uma lista ligada, com a cauda conhecer a sua regra de recorrência. Alterando um evento, então, seria fácil, porque as ligações permanecer no local e exclusão de um evento fácil é assim - você só desvincular um evento, excluí-lo e re-ligação do evento antes e depois dele. Você ainda tem que consulta eventos recorrentes cada vez que alguém olha para um novo período de tempo nunca foi olhado antes no calendário, mas por outro lado isso é muito limpo.

Você pode armazenar os eventos como a repetição, e se uma instância específica foi editado, criar um novo evento com o mesmo ID evento. Então, quando olhando para cima o evento, procurar todos os eventos com o mesmo ID de evento para obter todas as informações. Eu não tenho certeza se você rolou a sua própria biblioteca de eventos, ou se você estiver usando uma já existente de modo que não pode ser possível.

Confira o artigo abaixo para três boa data ruby ??/ hora bibliotecas. ice_cube em particular, parece uma escolha sólida para regras de recorrência e outras coisas que um calendário de eventos seria necessário. http://www.rubyinside.com /3-new-date-and-time-libraries-for-rubyists-3238.html

Em javascript:

Manipulação horários recorrentes: http://bunkat.github.io/later/

Manipulação de eventos complexos e dependências entre esses horários: http://bunkat.github.io/schedule/

Basicamente, você cria as regras, então você perguntar a lib para calcular a próxima N eventos recorrentes (especificando um intervalo de datas ou não). As regras podem ser analisados ??/ serializado para salvá-los em seu modelo.

Se você tem um evento recorrente e gostaria de modificar apenas uma recidiva você pode usar o , exceto () função de demitir um determinado dia e, em seguida, adicionar um novo evento modificado para esta entrada .

Os suportes lib muito complexos padrões, fusos horários e até mesmo Croning eventos.

Armazenar os eventos como a repetição e dinamicamente exibi-los, no entanto permitir que o evento recorrente para conter uma lista de eventos específicos que podem substituir as informações padrão em um dia específico.

Quando você consulta o evento recorrente pode verificar se há uma substituição específica para esse dia.

Se um usuário faz alterações, em seguida, você pode perguntar se ele quer atualizar para todas as instâncias (detalhes padrão) ou apenas naquele dia (fazer um novo evento específico e adicioná-lo à lista).

Se um usuário pede para apagar todas as recorrências deste evento você também tem a lista de especificações para mão e pode removê-los facilmente.

O único caso problemático seria se o usuário deseja atualizar esta todos os eventos futuros eventos e. Caso em que você vai ter que dividir o evento recorrente em dois. Neste ponto, você pode querer considerar que liga eventos recorrentes, de alguma forma para que você possa eliminá-los todos.

Para programadores .NET que estão preparados para pagar algumas taxas de licenciamento, você pode encontrar Aspose.Network útil ... ele inclui uma biblioteca compatível iCalendar para compromissos recorrentes.

Você armazena os eventos no formato iCalendar diretamente, o que permite a repetição aberto, localização de fuso horário e assim por diante.

Você pode armazenar estes em um servidor CalDAV e então quando você deseja exibir os eventos que você pode usar a opção do relatório definido no CalDAV para pedir o servidor para fazer a expansão dos eventos recorrentes em todo o período visualizado.

Ou você pode armazená-los em um banco de dados a si mesmo e usar algum tipo de iCalendar biblioteca de análise para fazer a expansão, sem a necessidade do PUT / GET / RELATÓRIO falar com um servidor back-end CalDAV. Este é provavelmente mais trabalho -. Tenho certeza de que em algum lugar servidores CalDAV hide complexidade

Tendo os eventos no formato iCalendar irá provavelmente tornar as coisas mais simples, a longo prazo, como as pessoas vão sempre quer que eles sejam exportados para colocar em outro software de qualquer maneira.

Eu simplesmente implementado esse recurso! A lógica é a seguinte, primeiro você precisa de duas tabelas. loja geral RuleTable ou reciclar eventos paternos. ItemTable é armazenado eventos do ciclo. Por exemplo, quando você cria um evento cíclico, a hora de início para 06 de novembro de 2015, o tempo final para o 06 de dezembro (ou para sempre), o ciclo de uma semana. Você inserir dados em uma RuleTable, os campos são os seguintes:

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.

Agora que você deseja consultar 20 de novembro a 20 de dezembro de dados. Você pode escrever uma função RecurringEventBE (long começar, final longo), com base no tempo inicial e final, semanal, você pode calcular a coleção que você quer, . Além disso a 6 de Novembro, eo resto eu o chamei um evento virtual. Quando o usuário altera um nome virtual evento' depois (cycleA11.27 por exemplo), você inserir uma dados em um ItemTable. Os campos são os seguintes:

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

Em função RecurringEventBE (long começar, final longo), você usar esses dados cobrindo evento virtual (cycleB11.27) Desculpe sobre o meu Inglês, eu tentei.

Este é o meu 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;
}   

E se você tem um compromisso recorrente sem data de término? Tão barato quanto o espaço é, você não tem espaço infinito, então Solução 2 é um non-starter lá ...

Posso sugerir que "nenhuma data final" pode ser resolvido para uma data final no final do século. Mesmo para um evento dayly a quantidade de espaço permanece barato.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top