From dd8955b823bb3e866665f2a16e1b37f2d2c41feb Mon Sep 17 00:00:00 2001 From: Philipp Kewisch Date: Wed, 1 May 2024 22:17:31 +0200 Subject: [PATCH 1/3] Add a compare function for ICAL.Period --- lib/ical/period.js | 18 +++++++++++++++ test/period_test.js | 53 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/lib/ical/period.js b/lib/ical/period.js index c8e44be0..c0c2eaaa 100644 --- a/lib/ical/period.js +++ b/lib/ical/period.js @@ -206,6 +206,24 @@ class Period { } } + /** + * Compare this period with a date or other period. To maintain the logic where a.compare(b) + * returns 1 when a > b, this function will return 1 when the period is after the date, 0 when the + * date is within the period, and -1 when the period is before the date. When comparing two + * periods, as soon as they overlap in any way this will return 0. + * + * @param {ICAL.Time|ICAL.Period} dt The date or other period to compare with + */ + compare(dt) { + if (dt.compare(this.start) < 0) { + return 1; + } else if (dt.compare(this.getEnd()) > 0) { + return -1; + } else { + return 0; + } + } + /** * The string representation of this period. * @return {String} diff --git a/test/period_test.js b/test/period_test.js index aac008b6..37ade250 100644 --- a/test/period_test.js +++ b/test/period_test.js @@ -312,4 +312,57 @@ suite('ical/period', function() { assert.equal(subject1.duration, subject2.duration); }); }); + + suite("#compare", function() { + test("with date", function() { + let subject = ICAL.Period.fromData({ + start: ICAL.Time.fromString("1970-01-02T03:04:04Z"), + end: ICAL.Time.fromString("1970-01-02T03:04:06Z") + }); + + let beforestart = ICAL.Time.fromString("1970-01-02T03:04:03Z"); + let between = ICAL.Time.fromString("1970-01-02T03:04:05Z"); + let afterend = ICAL.Time.fromString("1970-01-02T03:04:07Z"); + + assert.equal(subject.compare(beforestart), 1); + assert.equal(subject.compare(subject.start), 0); + assert.equal(subject.compare(between), 0); + assert.equal(subject.compare(subject.end), 0); + assert.equal(subject.compare(afterend), -1); + }); + + test("with other period", function() { + let subject = ICAL.Period.fromData({ + start: ICAL.Time.fromString("1970-01-02T03:04:04Z"), + end: ICAL.Time.fromString("1970-01-02T03:04:06Z") + }); + + let beforestart = ICAL.Period.fromData({ + start: ICAL.Time.fromString("1970-01-02T03:04:02Z"), + end: ICAL.Time.fromString("1970-01-02T03:04:03Z") + }); + let overlapstart = ICAL.Period.fromData({ + start: ICAL.Time.fromString("1970-01-02T03:04:03Z"), + end: ICAL.Time.fromString("1970-01-02T03:04:05Z") + }); + let within = ICAL.Period.fromData({ + start: ICAL.Time.fromString("1970-01-02T03:04:05Z"), + end: ICAL.Time.fromString("1970-01-02T03:04:05Z") + }); + let overlapend = ICAL.Period.fromData({ + start: ICAL.Time.fromString("1970-01-02T03:04:05Z"), + end: ICAL.Time.fromString("1970-01-02T03:04:07Z") + }); + let afterend = ICAL.Period.fromData({ + start: ICAL.Time.fromString("1970-01-02T03:04:07Z"), + end: ICAL.Time.fromString("1970-01-02T03:04:09Z") + }); + + assert.equal(subject.compare(beforestart), 1); + assert.equal(subject.compare(overlapstart), 0); + assert.equal(subject.compare(within), 0); + assert.equal(subject.compare(overlapend), 0); + assert.equal(subject.compare(afterend), -1); + }); + }); }); From 6ad6224869eb5e6d8491c2679f4fb3427ef80760 Mon Sep 17 00:00:00 2001 From: Philipp Kewisch Date: Wed, 1 May 2024 22:41:47 +0200 Subject: [PATCH 2/3] Add comparison for periods in ICAL.Time::compare --- lib/ical/time.js | 21 +++++++++++++-------- test/time_test.js | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/lib/ical/time.js b/lib/ical/time.js index 0ba05e7c..820ecc76 100644 --- a/lib/ical/time.js +++ b/lib/ical/time.js @@ -5,6 +5,7 @@ import Timezone from "./timezone.js"; import Duration from "./duration.js"; +import Period from "./period.js"; import design from "./design.js"; import TimezoneService from "./timezone_service.js"; import { strictParseInt, trunc, pad2 } from "./helpers.js"; @@ -965,18 +966,22 @@ class Time { } /** - * Compares the ICAL.Time instance with another one. + * Compares the ICAL.Time instance with another one, or a period. * - * @param {ICAL.Duration} aOther The instance to compare with - * @return {Number} -1, 0 or 1 for less/equal/greater + * @param {ICAL.Time|ICAL.Period} aOther The instance to compare with + * @return {Number} -1, 0 or 1 for less/equal/greater */ compare(other) { - let a = this.toUnixTime(); - let b = other.toUnixTime(); + if (other instanceof Period) { + return -1 * other.compare(this); + } else { + let a = this.toUnixTime(); + let b = other.toUnixTime(); - if (a > b) return 1; - if (b > a) return -1; - return 0; + if (a > b) return 1; + if (b > a) return -1; + return 0; + } } /** diff --git a/test/time_test.js b/test/time_test.js index 3fb59eab..59dd9879 100644 --- a/test/time_test.js +++ b/test/time_test.js @@ -1617,6 +1617,28 @@ suite('icaltime', function() { assert.equal(a.compare(b), 1); assert.equal(b.compare(a), -1); }); + + test("compare with period", function() { + let periodbefore = ICAL.Period.fromData({ + start: Time.fromString("1970-01-02T03:04:03Z"), + end: Time.fromString("1970-01-02T03:04:04Z") + }); + let periodat = ICAL.Period.fromData({ + start: Time.fromString("1970-01-02T03:04:05Z"), + end: Time.fromString("1970-01-02T03:04:05Z") + }); + let periodafter = ICAL.Period.fromData({ + start: Time.fromString("1970-01-02T03:04:06Z"), + end: Time.fromString("1970-01-02T03:04:07Z") + }); + + + let dt = Time.fromString('1970-01-02T03:04:05Z'); + + assert.equal(dt.compare(periodbefore), 1); + assert.equal(dt.compare(periodat), 0); + assert.equal(dt.compare(periodafter), -1); + }); }); test('cache cleared', function() { From 60fa389ff6c74d9ea1765ad356042f7c496c4ba6 Mon Sep 17 00:00:00 2001 From: Philipp Kewisch Date: Wed, 1 May 2024 22:48:26 +0200 Subject: [PATCH 3/3] Add test cases for period RDATEs --- samples/recur_instances.ics | 2 ++ test/recur_expansion_test.js | 10 +++++++--- test/time_test.js | 1 - 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/samples/recur_instances.ics b/samples/recur_instances.ics index 833f29b3..52b8320f 100644 --- a/samples/recur_instances.ics +++ b/samples/recur_instances.ics @@ -25,6 +25,8 @@ BEGIN:VEVENT UID:623c13c0-6c2b-45d6-a12b-c33ad61c4868 DESCRIPTION:IAM FOO RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=1TU +RDATE:20231123T090000Z +RDATE;VALUE=PERIOD:20231125T090000Z/20231125T123000Z SUMMARY:Crazy Event Thingy! ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Sahaja Lal;X-NUM-GUESTS=0:mailto:calmozilla1@gmail.com diff --git a/test/recur_expansion_test.js b/test/recur_expansion_test.js index eb5d37d1..dd016c7e 100644 --- a/test/recur_expansion_test.js +++ b/test/recur_expansion_test.js @@ -87,12 +87,16 @@ suite('recur_expansion', function() { let expected = [ new Date('2012-11-05T18:00:00.000Z'), new Date('2012-11-10T18:00:00.000Z'), - new Date('2012-11-30T18:00:00.000Z') - ]; + new Date('2012-11-30T18:00:00.000Z'), + // RDATEs + new Date('2023-11-23T09:00:00.000Z'), + new Date('2023-11-25T09:00:00.000Z') + ]; let dates = subject.ruleDates.map(function(time) { - return time.toJSDate(); + // We have a period in here, take the start date + return (time.start || time).toJSDate(); }); assert.deepEqual(dates, expected); diff --git a/test/time_test.js b/test/time_test.js index 59dd9879..5aac2d39 100644 --- a/test/time_test.js +++ b/test/time_test.js @@ -1632,7 +1632,6 @@ suite('icaltime', function() { end: Time.fromString("1970-01-02T03:04:07Z") }); - let dt = Time.fromString('1970-01-02T03:04:05Z'); assert.equal(dt.compare(periodbefore), 1);