1 import { convertZonedDateTimeToUTC, fromUTCDate, toUTCDate } from '../../date/timezone';
2 import type { VcalVeventComponent } from '../../interfaces/calendar';
3 import { propertyToUTCDate } from '../vcalConverter';
4 import { getPropertyTzid } from '../vcalHelper';
5 import { getIsAllDay } from '../veventHelper';
6 import type { RecurringResult } from './recurring';
7 import { getOccurrences, getOccurrencesBetween } from './recurring';
8 import { getIsRruleEqual } from './rruleEqual';
10 export const getAreOccurrencesSubset = (
11 newOccurrences: (RecurringResult | Pick<RecurringResult, 'localStart'>)[],
12 oldVevent: VcalVeventComponent
15 for (const { localStart } of newOccurrences) {
16 const isAllDay = getIsAllDay(oldVevent);
17 const startTzid = getPropertyTzid(oldVevent.dtstart);
18 let utcStart = localStart;
19 if (!isAllDay && startTzid) {
20 utcStart = toUTCDate(convertZonedDateTimeToUTC(fromUTCDate(localStart), startTzid));
22 const [oldOccurrence] = getOccurrencesBetween(oldVevent, +utcStart, +utcStart, cache);
31 * Return true if the set of occurrences of the new rrule is contained (equality counts) in the old rrule.
32 * Return false otherwise
33 * We restrict to rrules that can be created by us
35 export const getIsRruleSubset = (newVevent: VcalVeventComponent, oldVevent: VcalVeventComponent) => {
36 const [{ rrule: newRrule, dtstart: newDtstart }, { rrule: oldRrule }] = [newVevent, oldVevent];
37 const isRruleEqual = getIsRruleEqual(newRrule, oldRrule);
38 if (!newRrule || !oldRrule || isRruleEqual) {
41 const { count: oldCount, until: oldUntil } = oldRrule.value;
42 const { count: newCount, until: newUntil } = newRrule.value;
43 if (!newCount && !newUntil && (oldCount || oldUntil)) {
47 * Given the repeating nature of recurring rules, we're gonna play dirty here
48 * and simply check if the at max 10 first occurrences of the new recurring rule are generated by the old one.
49 * For the recurring rules we support this is more than enough, but it wouldn't be
50 * in a more general (and pathological) scenario.
51 * The alternative would be to write some code checking the frequency, interval,
52 * byday, etc properties and going case by case. That code would be cumbersome and ugly
54 // either newUntil or newCount are not undefined, so we can check if all new occurrences are in the original set
55 // but for performance we use the same trick as above and check max 10
56 const maxCount = newCount ? Math.min(newCount, 10) : 10;
57 const newOccurrences = newUntil
58 ? getOccurrencesBetween(newVevent, +propertyToUTCDate(newDtstart), +toUTCDate(newUntil)).slice(0, 10)
59 : getOccurrences({ component: newVevent, maxCount });
61 return getAreOccurrencesSubset(newOccurrences, oldVevent);