中断重复事件时 RRULE 中 UNTIL 的值

Value of UNTIL in RRULE when breaking a repeat event

考虑以下 Google 日历中的重复事件,其 RRULE 如下所述。

BEGIN:VEVENT
DTSTART;TZID=Asia/Calcutta:20170111T020000
DTEND;TZID=Asia/Calcutta:20170111T050000
RRULE:FREQ=DAILY;UNTIL=20170116T203000Z
DTSTAMP:20170110T150957Z
CREATED:20170110T150942Z
DESCRIPTION:
LAST-MODIFIED:20170110T150942Z
LOCATION:
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:Repeat event test
TRANSP:OPAQUE
END:VEVENT

如果现在通过在 1 月 14 日将重复系列分成两部分(编辑此事件和未来事件)来编辑此事件,则此事件的 RRULE 更改为以下内容

RRULE:FREQ=DAILY;UNTIL=20170113T182959Z

为什么UNTIL的值设置为1秒小于1月14日重现的RECURRENCEID/DTSTART值,而不是设置为1月14日重现的DTSTART值1月13日复发。是否有标准规定在这种情况下RRULE中的UNTIL值必须以这种方式设置(即少1秒)?

您不会找到任何提及此内容的标准。 https://www.rfc-editor.org/rfc/rfc5545#section-3.3.10 提到如何

If the value specified by UNTIL is synchronized with the specified recurrence, this DATE or DATE-TIME becomes the last instance of the recurrence.

但它没有强制要求该值必须与循环同步,也没有提到它应该少 1 秒。

我怀疑这只是开发人员的方便,因为截止日期是他正在操纵的 14 日,而之前的实例将需要计算。

public String pushAppointmentsToCalender(Activity curActivity, String title, String addInfo, long startDate, boolean needReminder) {
    try {
        String eventUriString = "content://com.android.calendar/events";
        ContentValues eventValues = new ContentValues();
        eventValues.put("calendar_id", 1); // id, We need to choose from
        // our mobile for primary
        //CalendarContract.EXTRA_EVENT_END_TIME
        // its 1
        eventValues.put("title", title);
        eventValues.put("description", addInfo);
        eventValues.put("dtstart", startDate);
        eventValues.put("dtend", startDate);

        String untileDate = "20220515";
        switch (repeatSelection) {
            case "Every Day":
                if (!untileDate.equals("")) {
                    eventValues.put("rrule", "FREQ=DAILY;UNTIL=" + untileDate);
                } else {
                    eventValues.put("rrule", "FREQ=DAILY");
                }
                break;
            case "Every Week":
                if (!untileDate.equals("")) {
                    eventValues.put("rrule", "FREQ=WEEKLY;UNTIL=" + untileDate);
                } else {
                    eventValues.put("rrule", "FREQ=WEEKLY");
                }
                break;
            case "Every Month":
                if (!untileDate.equals("")) {
                    eventValues.put("rrule", FREQ=MONTHLY;UNTIL=" + untileDate);

                } else {
                    eventValues.put("rrule", "FREQ=MONTHLY");
                }
                break;
            case "Custom":
                switch (frequency) {
                    case "1":
                        if (!untileDate.equals("")) {
                            eventValues.put("rrule", "FREQ=DAILY;INTERVAL=" + Integer.parseInt(every) + ";UNTIL=" + untileDate);
                        } else {
                            eventValues.put("rrule", "FREQ=DAILY;INTERVAL=" + Integer.parseInt(every));
                        }
                        break;
                    case "3":
                        if (!untileDate.equals("")) {
                            eventValues.put("rrule", "FREQ=WEEKLY;INTERVAL=" + Integer.parseInt(every) + ";UNTIL=" + untileDate);
                        } else {
                            eventValues.put("rrule", "FREQ=WEEKLY;INTERVAL=" + Integer.parseInt(every));
                        }
                        break;
                    case "2":
                        if (!untileDate.equals("")) {
                            eventValues.put("rrule", "FREQ=MONTHLY;INTERVAL=" + Integer.parseInt(every) + ";UNTIL=" + untileDate);
                        } else {
                            eventValues.put("rrule", "FREQ=MONTHLY;INTERVAL=" + Integer.parseInt(every));
                        }
                        break;
                    case "4":
                        if (!untileDate.equals("")) {
                            eventValues.put("rrule", "FREQ=YEARLY;INTERVAL=" + Integer.parseInt(every) + ";UNTIL=" + untileDate);
                        } else {
                            eventValues.put("rrule", "FREQ=YEARLY;INTERVAL=" + Integer.parseInt(every));
                        }
                        break;
                }
                break;
        }

        eventValues.put("allDay", 0); //If it is bithday alarm or such
        // kind (which should remind me for whole day) 0 for false, 1
        // for true
        eventValues.put("eventStatus", 1); // This information is
        TimeZone timeZone = TimeZone.getDefault();
        eventValues.put(CalendarContract.Events.EVENT_TIMEZONE, timeZone.getID());
        eventValues.put("hasAlarm", 1); // 0 for false, 1 for true

        Uri eventUri = curActivity.getApplicationContext().getContentResolver().insert(Uri.parse(eventUriString), eventValues);
        long eventID = Long.parseLong(eventUri.getLastPathSegment());

        if (needReminder) {
            /**************** Event: Reminder(with alert) Adding reminder to event ******************/
            String reminderUriString = "content://com.android.calendar/reminders";
            ContentValues reminderValues = new ContentValues();
            reminderValues.put("event_id", eventID);
            reminderValues.put("minutes", 10); // Default value of the
            // system. Minutes is a
            // integer
            reminderValues.put("method", 1); // Alert Methods: Default(0),
            // Alert(1), Email(2),
            // SMS(3)
            Uri reminderUri = curActivity.getApplicationContext().getContentResolver().insert(Uri.parse(reminderUriString), reminderValues);
        }
        return "" + eventID;
    } catch (Exception e) {
        e.printStackTrace();
        return "";
    }
}

repeatSelection type =Every Day,Every Week,Every Month,Custom; frequency type =1,2,3,4; when you select custom frequency type 1 = DAILY,2=MONTHLY,3=WEEKLY,4 YEARLY;