241

定期的なイベントをサポートする必要があるグループ カレンダー アプリケーションを構築していますが、これらのイベントを処理するために思いついたソリューションはすべてハックのようです。どれだけ先を見ることができるかを制限し、すべてのイベントを一度に生成できます。または、イベントを繰り返しとして保存し、カレンダーを先に見たときに動的に表示することもできますが、イベントの特定のインスタンスの詳細を変更したい場合は、通常のイベントに変換する必要があります。

これを行うためのより良い方法があると確信していますが、まだ見つけていません。特定のイベント インスタンスの詳細を変更または削除できる定期的なイベントをモデル化する最良の方法は何ですか?

(私は Ruby を使用していますが、それがあなたの答えを制限しないようにしてください。Ruby 固有のライブラリなどがある場合は、知っておくとよいでしょう。)

4

17 に答える 17

104

今後のすべての定期的なイベントには「リンク」の概念を使用します。これらはカレンダーに動的に表示され、単一の参照オブジェクトにリンクされます。イベントが発生すると、リンクが切断され、イベントはスタンドアロン インスタンスになります。定期的なイベントを編集しようとすると、将来のすべてのアイテムを変更する (つまり、単一のリンクされた参照を変更する) か、そのインスタンスだけを変更する (この場合、これをスタンドアロン インスタンスに変換してから変更する) ように求められます。後者の場合は、単一インスタンスに変換された将来のすべてのイベントの定期的なリストを追跡する必要があるため、少し問題があります。しかし、これは完全に実行可能です。

したがって、本質的に、単一インスタンスと定期的なイベントの 2 つのクラスのイベントがあります。

于 2008-09-17T17:45:23.977 に答える
44

複数のカレンダーベースのアプリケーションを開発し、繰り返しをサポートする再利用可能な一連の JavaScript カレンダー コンポーネントも作成しました。誰かに役立つかもしれない再発を設計する方法の概要を書きました。私が作成したライブラリに固有の部分がいくつかありますが、提供されるアドバイスの大部分は、カレンダーの実装に一般的なものです。

いくつかの重要なポイント:

  • iCal RRULE 形式を使用して繰り返しを保存します。これは、再発明したくない車輪の 1 つです。
  • 個々の定期的なイベントインスタンスをデータベースの行として保存しないでください。繰り返しパターンを常に保存します。
  • イベント/例外スキーマを設計するには多くの方法がありますが、基本的な出発点の例が提供されています
  • すべての日付/時刻の値は UTC で保存し、表示用にローカルに変換する必要があります
  • 定期的なイベントに保存される終了日は、常に繰り返し範囲の終了日(または、「永久に」繰り返される場合はプラットフォームの「最大日付」) である必要があり、イベント期間は個別に保存する必要があります。これは、後でイベントを照会する適切な方法を確保するためです。詳細については、リンク先の記事をお読みください。
  • イベント インスタンスの生成と繰り返し編集戦略に関するいくつかの議論が含まれています。

それを実装するための非常に多くの有効なアプローチがある、非常に複雑なトピックです。私は実際に再発を何度か成功裏に実装したと言いますが、実際に再帰を実行したことがない人からこの件についてアドバイスを受けるのは慎重です.

于 2016-07-13T18:25:42.907 に答える
34

定期的なイベントには多くの問題が発生する可能性があります。私が知っているいくつかの問題を紹介します。

解決策 1 - インスタンスなし

すべてのインスタンスを保存するのではなく、元の予定と定期的なデータを保存します。

問題:

  • 必要なときに日付ウィンドウ内のすべてのインスタンスを計算する必要があり、費用がかかります
  • 例外を処理できません (つまり、インスタンスの 1 つを削除するか移動するか、このソリューションではこれを行うことができません)。

解決策 2 - インスタンスを保存する

1 からすべてを保存するだけでなく、元の予定にリンクされたすべてのインスタンスも保存します。

問題:

  • 多くのスペースを必要とします(ただし、スペースは安価なのでマイナーです)
  • 特に、例外を作成した後に元の予定に戻って編集する場合は、例外を適切に処理する必要があります。たとえば、3 番目のインスタンスを 1 日進めた場合、戻って元の予定の時間を編集し、元の日に別の予定を再挿入して、移動した予定を残した場合はどうなるでしょうか。移動したもののリンクを解除しますか? 移動したものを適切に変更してみてください。

もちろん、例外を行うつもりがない場合は、どちらのソリューションでも問題なく、基本的に時間/空間のトレードオフのシナリオから選択します。

于 2009-05-19T11:38:01.057 に答える
20

iCalendar ソフトウェアの実装または標準そのもの ( RFC 2445 RFC 5545 ) を参照することをお勧めします。すぐに思いつくのは Mozilla プロジェクトですhttp://www.mozilla.org/projects/calendar/ 簡単な検索でhttp://icalendar.rubyforge.org/も見つかります。

イベントを保存する方法に応じて、他のオプションを検討できます。独自のデータベース スキーマを構築していますか? iCalendar ベースのものなどを使用していますか?

于 2008-09-17T17:40:52.880 に答える
16

私は以下を扱っています:

そして、入力タイプ :recurring ( ) で formtastic を拡張する進行中の gemform.schedule :as => :recurringは、iCal のようなインターフェイスをレンダリングしbefore_filter、ビューをIceCubeオブジェクトに再びシリアル化します。

私の考えは、繰り返し属性をモデルに追加し、それをビューで簡単に接続することを信じられないほど簡単にすることです。すべて数行で。


それで、これは私に何を与えますか?インデックス付き、編集可能、繰り返し属性。

events単一の日のインスタンスをtask.schedule格納し、yaml 化されたIceCubeオブジェクトを格納するカレンダー ビュー/ヘルパーで使用されるため、 : のような呼び出しを行うことができますtask.schedule.next_suggestion

要約: 私は 2 つのモデルを使用します。1 つはカレンダー表示用のフラットで、もう 1 つは機能用の属性です。

于 2010-10-23T00:19:24.833 に答える
7

以下で説明するデータベース スキーマを使用して、繰り返しパラメーターを保存しています。

http://github.com/bakineggs/recurring_events_for

次に、runt を使用して日付を動的に計算します。

https://github.com/mlipper/runt

于 2009-11-09T03:07:33.283 に答える
5
  1. 繰り返しルールを追跡します (@ Kris K.によると、おそらく iCalendar に基づいています)。これには、パターンと範囲が含まれます (第 3 火曜日ごとに 10 回発生)。
  2. 特定の発生を編集/削除する場合は、上記の繰り返しルールの例外日 (ルールで指定されたイベントが発生しない日付) を追跡します。
  3. 削除した場合はこれで十分です。編集した場合は別のイベントを作成し、親 ID をメイン イベントに設定します。このレコードにメイン イベントのすべての情報を含めるか、変更のみを保持し、変更されていないすべてを継承するかを選択できます。

終了しない繰り返しルールを許可する場合は、現在無限の情報量を表示する方法を考える必要があることに注意してください。

それが役立つことを願っています!

于 2008-09-17T17:50:15.040 に答える
4

date ライブラリの力と ruby​​ の range モジュールのセマンティクスを利用することをお勧めします。定期的なイベントは、実際には時間、日付範囲 (開始日と終了日) であり、通常は 1 つの曜日です。日付と範囲を使用すると、質問に答えることができます。

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

うるう年も含めて全日プロデュース!

# =>"[\"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\"]"
于 2008-09-17T18:01:01.583 に答える
3

これらの答えから、私は解決策をふるいにかけました。リンクのコンセプトがとても気に入っています。定期的なイベントは、その繰り返しルールを認識している末尾を持つリンクされたリストにすることができます。1 つのイベントを変更するのは簡単です。これは、リンクがそのまま残るためです。また、イベントの削除も簡単です。イベントのリンクを解除して削除し、その前後のイベントを再度リンクするだけです。誰かがカレンダーで以前に見たことのない新しい期間を見るたびに、定期的なイベントを照会する必要がありますが、それ以外は非常にきれいです。

于 2008-09-17T18:04:56.597 に答える
2

Ruby の 3 つの優れた日付/時刻ライブラリについては、以下の記事を参照してください。特に ice_cube は、イベント カレンダーに必要な繰り返しルールやその他のものに最適な選択肢のようです。 http://www.rubyinside.com/3-new-date-and-time-libraries-for-rubyists-3238.html

于 2011-02-11T10:31:33.077 に答える
2

イベントを繰り返しとして保存し、特定のインスタンスが編集された場合は、同じイベント ID で新しいイベントを作成できます。次に、イベントを検索するときに、同じイベント ID を持つすべてのイベントを検索して、すべての情報を取得します。独自のイベント ライブラリを展開したのか、それとも既存のイベント ライブラリを使用しているのかはわかりませんが、それは不可能かもしれません。

于 2008-09-17T17:44:16.897 に答える
1

JavaScript の場合:

定期的なスケジュールの処理: http://bunkat.github.io/later/

これらのスケジュール間の複雑なイベントと依存関係の処理: http://bunkat.github.io/schedule/

基本的に、ルールを作成してから、ライブラリに次の N 個の定期的なイベントを計算するように依頼します (日付範囲を指定するかどうかを指定します)。ルールは、モデルに保存するために解析/シリアル化できます。

定期的なイベントがあり、1 つの繰り返しのみを変更したい場合は、except()関数を使用して特定の日を閉じてから、このエントリに新しい変更済みイベントを追加できます。

lib は、非常に複雑なパターン、タイムゾーン、さらには croning イベントをサポートしています。

于 2014-11-23T10:18:26.843 に答える
0

ライセンス料を支払う準備ができている.NETプログラマーにとって、Aspose.Networkが役立つかもしれません...これには、定期的な予定のためのiCalendar互換ライブラリが含まれています。

于 2009-05-19T11:28:11.700 に答える
0

イベントを繰り返しとして保存し、動的に表示しますが、定期的なイベントには、特定の日のデフォルト情報を上書きできる特定のイベントのリストを含めることができます。

定期的なイベントを照会すると、その日の特定の上書きを確認できます。

ユーザーが変更を行った場合、すべてのインスタンス (デフォルトの詳細) を更新するか、その日だけ更新するか (新しい特定のイベントを作成してリストに追加) を尋ねることができます。

ユーザーがこのイベントのすべての繰り返しを削除するように要求した場合は、詳細のリストも手元にあり、簡単に削除できます。

唯一の問題は、ユーザーがこのイベントと将来のすべてのイベントを更新したい場合です。その場合、定期的なイベントを 2 つに分割する必要があります。この時点で、定期的なイベントを何らかの方法でリンクして、それらをすべて削除できるようにすることを検討してください。

于 2008-09-17T17:47:11.350 に答える
0

この機能を簡単に実装しました!ロジックは次のとおりです。まず、2 つのテーブルが必要です。RuleTable は、一般的なイベントまたは父親のイベントをリサイクルします。ItemTable は、格納されたサイクル イベントです。たとえば、周期的なイベントを作成する場合、2015 年 11 月 6 日の開始時刻、12 月 6 日の終了時刻 (または無期限) を 1 週間サイクルします。RuleTable にデータを挿入します。フィールドは次のとおりです。

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.

次に、11 月 20 日から 12 月 20 日までのデータをクエリします。関数 RecurringEventBE (長い開始、長い終了) を記述して、開始時間と終了時間 WeekLy に基づいて、必要なコレクションを計算できます < cycleA11.20, cycleA 11.27, cycleA 12.4 ......>. 11 月 6 日に加えて、私は彼を仮想イベントと呼びました。ユーザーが後で仮想イベントの名前を変更すると (たとえば、cycleA11.27)、ItemTable にデータを挿入します。フィールドは次のとおりです。

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

関数 RecurringEventBE (長い開始、長い終了) では、仮想イベント (cycleB11.27) をカバーするこのデータを使用します。

これは私の RecurringEventBE です:</p>

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;
}   
于 2014-11-06T02:31:12.657 に答える
0

イベントは iCalendar 形式で直接保存します。これにより、無制限の繰り返し、タイムゾーンのローカリゼーションなどが可能になります。

これらをCalDAVサーバーに保存し、イベントを表示したい場合は、CalDAVで定義されたレポートのオプションを使用して、表示された期間にわたって繰り返しイベントを展開するようサーバーに依頼できます.

または、それらを自分でデータベースに保存し、ある種の iCalendar 解析ライブラリを使用して拡張を行うこともできます。PUT/GET/REPORT でバックエンドの CalDAV サーバーと通信する必要はありません。これはおそらくより多くの作業です。CalDAV サーバーはどこかに複雑さを隠していると確信しています。

イベントを iCalendar 形式にすることで、他のソフトウェアに入れるためにエクスポートすることを常に望んでいるため、長期的には物事が簡単になるでしょう。

于 2012-03-14T01:38:51.467 に答える
-5

終了日がない定期的な予定がある場合はどうなりますか?スペースは安いですが、無限のスペースはありません。そのため、ソリューション2は初心者ではありません...

「終了日なし」は、世紀末の終了日に解決できることをお勧めします。毎日のイベントでも、スペースの量は安いままです。

于 2010-02-01T14:12:37.647 に答える