diff --git a/ical.js b/ical.js index 33b26d6..916fd3b 100644 --- a/ical.js +++ b/ical.js @@ -458,11 +458,10 @@ module.exports = { curr.end = (curr.datetype === 'date-time') ? new Date(curr.start.getTime()) : moment.utc(curr.start).add(1, 'days').toDate(); // If there was a duration specified + // see RFC5545, 3.3.6 (no year and month) if (curr.duration !== undefined) { const durationUnits = { - // Y: 'years', - // M: 'months', W: 'weeks', D: 'days', H: 'hours', @@ -470,15 +469,26 @@ module.exports = { S: 'seconds' }; // Get the list of duration elements - const r = curr.duration.match(/-?\d{1,10}[YMWDHS]/g); + const duration = curr.duration.match(/-?\d{1,10}[WDHMS]/g); // Use the duration to create the end value, from the start - let newend = moment.utc(curr.start); + const startMoment = moment.utc(curr.start); + let newEnd = startMoment; + // Is the 1st character a negative sign? const indicator = curr.duration.startsWith('-') ? -1 : 1; - newend = newend.add(Number.parseInt(r, 10) * indicator, durationUnits[r.toString().slice(-1)]); + + for (const r of duration) { + const unit = r.slice(-1); + if (!durationUnits[unit]) { + throw new Error(`Invalid duration unit: ${unit}`); + } + + newEnd = newEnd.add(Number.parseInt(r, 10) * indicator, durationUnits[r.toString().slice(-1)]); + } + // End is a Date type, not moment - curr.end = newend.toDate(); + curr.end = newEnd.toDate(); } } diff --git a/test/test-async.js b/test/test-async.js index 220bd08..e86d218 100644 --- a/test/test-async.js +++ b/test/test-async.js @@ -851,7 +851,7 @@ vows }, 'it uses the start/end of the event'(event) { assert.equal(event.start.toJSON(), '2024-02-15T09:00:00.000Z'); - assert.equal(event.end.toJSON(), '2024-02-15T09:15:00.000Z'); + assert.equal(event.end.toJSON(), '2024-02-15T10:15:00.000Z'); } } }, diff --git a/test/test.js b/test/test.js index ddff525..2aefbfb 100644 --- a/test/test.js +++ b/test/test.js @@ -1041,7 +1041,7 @@ vows }, 'it uses the start/end of the event'(event) { assert.equal(event.start.toJSON(), '2024-02-15T09:00:00.000Z'); - assert.equal(event.end.toJSON(), '2024-02-15T09:15:00.000Z'); + assert.equal(event.end.toJSON(), '2024-02-15T10:15:00.000Z'); } } }, diff --git a/test/test_date_time_duration.ics b/test/test_date_time_duration.ics index f9ba846..b4308e8 100644 --- a/test/test_date_time_duration.ics +++ b/test/test_date_time_duration.ics @@ -13,6 +13,6 @@ DESCRIPTION: LOCATION:Kriftel X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-TITLE=Kriftel: geo:50.083558\,8.4693855 DTSTART:20240215T090000Z -DURATION:PT15M +DURATION:PT1H15M END:VEVENT END:VCALENDAR